Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Giehl <stefan@piwik.org>2017-09-04 07:49:32 +0300
committerMatthieu Aubry <mattab@users.noreply.github.com>2017-09-04 07:49:32 +0300
commit660df51720386077f0a1433d86bcb96ef002de35 (patch)
treeb953fcb22811d3e76f752713eee1c619b6d82098 /plugins
parentb40a997defdea7ba6984b268bb7c791d089cfd3f (diff)
Customizeable / Extendable Visitor Profile & Visitor Log (#11579)
* move setting visitor details into own classes instead of using an event * move manipulating actions to VisitorDetails classes * move some more parts to plugins * update test files as order of columns changed * implement new VisitorDetails method to provide actions * move rendering actions to visitordetail classes * render visitor properties in new classes * makes it possible to attach icons to visitor log * moves rendering of action tooltip into new visitordetails method * adds event for extending custom action dimension fields * small improvements * fetch log_link_visit_action.idpageview for actions * improve variable name * started to improve/change visitor profile * show devices summary in visitor profile * also remove empty xml tags for api tests * hide actions in visitor profile by default * move all icons to the middle of visitor log * small change * move rendering referrer information to referrers plugin * move provider logic to provider plugin * show content interactions in visitor log * improve look of content interactions/impressions in visitor log / profile * hide idpageview from tests * update changelog * move rendering events to Events plugin * do not hide duplicate page views in visitor log, but show them with a refresh icon instead * show top visited pages in visitor profile * always show visitor profile link in visitor log Still hidden in a widget by default, as it might overlay some other content * Show info about not shown actions truncated due to config setting * use bulk queries to fetch actions instead of fetching them for each visit * small adjustments * improve some loops to improve memory usage * move gathering visitor profile informations to VisitorDetails classes * update screenshots * update test files * move rendering of visitor profile summary to visitor details classes * improve templates * Makes VisitorDetailsAbstract class api and improves comments * show visit details in visitor profile * improve css * reverse enumeration of visits in visitor profile * improve css * Show visit id in IP tooltip * Small CSS improvements * further adjustments * sort devices by count * adds UI tests for visitor log and profile * Show bandwidth in visitor profile test * show actions by default and add button to toggle all together * CSS cleanup * remove border around refresh icon * add tooltip for refresh icon in profile * move first/last visit before top visited pages * Improve text shown for unique pageviews * link urls in top visited pages * improve sorting of device list * improve tests * Improve device overview in visitor profile * only render top pages if at least one page was visited more than once * make visitor id non bold * hide visitor type icon in profile, and show latest visits icons in overview * fix search engine icon in visitor details * small improvements * only render view if required * show visit icons only on hover in profile * remove from again * test improves * show text besides icon in profile header * improve tests * Removes unused CSS and JS * Reformats CSS * Removes invisible paper clip * Removes unused profile images from Live plugin * raise test timeouts * Improve UI tests splitting for travis * show device type in profile header if no resolution is available * prevent text overlapping * no retries * fix test * change summary order * fix position of export icon * fixes tooltip text * improve pages overview * visitor details order * action tooltip order * show only ecommerce icon if no goals where converted * show custom variables summary in profile * show user id in same size as headline * link referer urls for first/last visit in profile * make profile xml compatible * try to improve ui test * increase bottom marign * increase version number * small adjustments * CSS Rewrite for visitor profile * center action icons in visitor log and profile * improve widgetized visitor profile * small layout fix * always populate raw referrer url for visitor details * update expected test files * Refactor profile summaries into additional classes * update screenshots * submodule update * update piwik-icons submodule (#11904) * update piwik-icons submodule * fix some system tests * update screenshots * make device list xml compatible * improve translation * improve icon position * improves spacings * update test files * small css improvement * update screenshots
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Actions/Actions.php8
-rw-r--r--plugins/Actions/VisitorDetails.php373
-rw-r--r--plugins/Actions/lang/en.json2
-rw-r--r--plugins/Actions/templates/_profileSummary.twig25
m---------plugins/Bandwidth0
-rw-r--r--plugins/Contents/Contents.php18
-rw-r--r--plugins/Contents/VisitorDetails.php50
-rw-r--r--plugins/Contents/lang/en.json1
-rw-r--r--plugins/Contents/templates/_actionContent.twig15
-rw-r--r--plugins/Contents/templates/_actionTooltip.twig9
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml444
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml444
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml444
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml444
-rw-r--r--plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml444
-rw-r--r--plugins/CoreHome/CoreHome.php20
-rw-r--r--plugins/CoreHome/Visitor.php114
-rw-r--r--plugins/CoreHome/VisitorDetails.php119
m---------plugins/CustomDimensions0
-rw-r--r--plugins/CustomVariables/CustomVariables.php29
-rw-r--r--plugins/CustomVariables/ProfileSummary/VisitScopeSummary.php56
-rw-r--r--plugins/CustomVariables/VisitorDetails.php203
-rw-r--r--plugins/CustomVariables/templates/_actionTooltip.twig10
-rw-r--r--plugins/CustomVariables/templates/_profileSummary.twig13
-rw-r--r--plugins/CustomVariables/templates/_visitorDetails.twig13
-rw-r--r--plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml28
-rw-r--r--plugins/DevicePlugins/DevicePlugins.php9
-rw-r--r--plugins/DevicePlugins/VisitorDetails.php (renamed from plugins/DevicePlugins/Visitor.php)17
-rw-r--r--plugins/DevicesDetection/DevicesDetection.php34
-rw-r--r--plugins/DevicesDetection/ProfileSummary/DevicesSummary.php52
-rw-r--r--plugins/DevicesDetection/Visitor.php101
-rw-r--r--plugins/DevicesDetection/VisitorDetails.php175
-rw-r--r--plugins/DevicesDetection/lang/en.json1
-rw-r--r--plugins/DevicesDetection/templates/_profileSummary.twig21
-rw-r--r--plugins/Ecommerce/ProfileSummary/EcommerceSummary.php54
-rw-r--r--plugins/Ecommerce/VisitorDetails.php216
-rw-r--r--plugins/Ecommerce/templates/_profileSummary.twig14
-rw-r--r--plugins/Events/Events.php17
-rw-r--r--plugins/Events/VisitorDetails.php56
-rw-r--r--plugins/Events/templates/_actionEvent.twig25
-rw-r--r--plugins/Goals/VisitorDetails.php124
-rw-r--r--plugins/Live/API.php38
-rw-r--r--plugins/Live/Controller.php106
-rw-r--r--plugins/Live/Live.php64
-rw-r--r--plugins/Live/Model.php194
-rw-r--r--plugins/Live/ProfileSummary/ImportantVisits.php47
-rw-r--r--plugins/Live/ProfileSummary/ProfileSummaryAbstract.php67
-rw-r--r--plugins/Live/ProfileSummary/Summary.php52
-rw-r--r--plugins/Live/Visitor.php337
-rw-r--r--plugins/Live/VisitorDetails.php252
-rw-r--r--plugins/Live/VisitorDetailsAbstract.php275
-rw-r--r--plugins/Live/VisitorProfile.php347
-rw-r--r--plugins/Live/images/avatar_frame.pngbin5375 -> 0 bytes
-rw-r--r--plugins/Live/images/paperclip.pngbin10924 -> 0 bytes
-rw-r--r--plugins/Live/images/visitor_profile_close.pngbin4734 -> 0 bytes
-rw-r--r--plugins/Live/images/visitor_profile_gradient.pngbin2840 -> 0 bytes
-rw-r--r--plugins/Live/javascripts/visitorLog.js50
-rw-r--r--plugins/Live/javascripts/visitorProfile.js63
-rw-r--r--plugins/Live/lang/en.json4
-rw-r--r--plugins/Live/stylesheets/live.less93
-rw-r--r--plugins/Live/stylesheets/visitor_profile.less775
-rw-r--r--plugins/Live/templates/_actionCommon.twig38
-rw-r--r--plugins/Live/templates/_actionEcommerce.twig54
-rw-r--r--plugins/Live/templates/_actionGoal.twig11
-rw-r--r--plugins/Live/templates/_actionTooltip.twig8
-rw-r--r--plugins/Live/templates/_actionsList.twig135
-rw-r--r--plugins/Live/templates/_dataTableViz_visitorLog.twig187
-rw-r--r--plugins/Live/templates/_profileSummary.twig38
-rw-r--r--plugins/Live/templates/_profileSummaryVisits.twig39
-rw-r--r--plugins/Live/templates/_visitorDetails.twig17
-rw-r--r--plugins/Live/templates/_visitorLogIcons.twig84
-rw-r--r--plugins/Live/templates/getSingleVisitSummary.twig68
-rw-r--r--plugins/Live/templates/getVisitList.twig42
-rw-r--r--plugins/Live/templates/getVisitorProfilePopup.twig204
-rw-r--r--plugins/Live/tests/Fixtures/VisitsWithAllActionsAndDevices.php221
-rw-r--r--plugins/Live/tests/System/expected/test___Live.getVisitorProfile.xml396
-rw-r--r--plugins/Live/tests/System/expected/test_higherLimit__Live.getVisitorProfile.xml666
-rw-r--r--plugins/Live/tests/UI/Live_spec.js58
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_log.pngbin0 -> 417726 bytes
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile.pngbin0 -> 436620 bytes
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_details.pngbin0 -> 301651 bytes
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_tooltip.pngbin0 -> 11399 bytes
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_actions_hidden.pngbin0 -> 261870 bytes
-rw-r--r--plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_visit_details.pngbin0 -> 271958 bytes
m---------plugins/MarketingCampaignsReporting0
m---------plugins/Morpheus/icons0
-rw-r--r--plugins/Morpheus/images/event.pngbin164 -> 2843 bytes
-rw-r--r--plugins/Morpheus/stylesheets/general/_default.less1
-rw-r--r--plugins/Morpheus/stylesheets/main.less154
-rw-r--r--plugins/ProfessionalServices/templates/promoSessionRecordings.twig2
-rw-r--r--plugins/Provider/Provider.php19
-rw-r--r--plugins/Provider/Visitor.php41
-rw-r--r--plugins/Provider/VisitorDetails.php57
-rw-r--r--plugins/Provider/templates/_visitorDetails.twig9
-rw-r--r--plugins/Referrers/Referrers.php15
-rw-r--r--plugins/Referrers/VisitorDetails.php (renamed from plugins/Referrers/Visitor.php)65
-rw-r--r--plugins/Referrers/templates/_visitorDetails.twig35
-rw-r--r--plugins/Resolution/Resolution.php19
-rw-r--r--plugins/Resolution/VisitorDetails.php (renamed from plugins/Resolution/Visitor.php)14
-rw-r--r--plugins/UserCountry/ProfileSummary/LocationSummary.php80
-rw-r--r--plugins/UserCountry/UserCountry.php18
-rw-r--r--plugins/UserCountry/Visitor.php115
-rw-r--r--plugins/UserCountry/VisitorDetails.php198
-rw-r--r--plugins/UserCountry/templates/_profileSummary.twig40
-rw-r--r--plugins/UserLanguage/UserLanguage.php18
-rw-r--r--plugins/UserLanguage/VisitorDetails.php (renamed from plugins/UserLanguage/Visitor.php)17
-rw-r--r--plugins/VisitTime/VisitTime.php16
-rw-r--r--plugins/VisitTime/VisitorDetails.php20
-rw-r--r--plugins/VisitorInterest/VisitorDetails.php19
-rw-r--r--plugins/VisitorInterest/VisitorInterest.php17
110 files changed, 6926 insertions, 3335 deletions
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index 409940d495..35c673e716 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -30,19 +30,11 @@ class Actions extends \Piwik\Plugin
'ViewDataTable.configure' => 'configureViewDataTable',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Insights.addReportToOverview' => 'addReportToInsightsOverview',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations',
);
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $visitor['searches'] = $details['visit_total_searches'];
- $visitor['actions'] = $details['visit_total_actions'];
- $visitor['interactions'] = $details['visit_total_interactions'];
- }
-
public function addMetricTranslations(&$translations)
{
$metrics = array(
diff --git a/plugins/Actions/VisitorDetails.php b/plugins/Actions/VisitorDetails.php
new file mode 100644
index 0000000000..7292bd87f5
--- /dev/null
+++ b/plugins/Actions/VisitorDetails.php
@@ -0,0 +1,373 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions;
+
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\Date;
+use Piwik\Db;
+use Piwik\Metrics\Formatter;
+use Piwik\Piwik;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Site;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\PageUrl;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ const EVENT_VALUE_PRECISION = 3;
+
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['searches'] = $this->details['visit_total_searches'];
+ $visitor['actions'] = $this->details['visit_total_actions'];
+ $visitor['interactions'] = $this->details['visit_total_interactions'];
+ }
+
+ public function provideActionsForVisitIds(&$actions, $visitIds)
+ {
+ $actionDetails = $this->queryActionsForVisits($visitIds);
+ // use while / array_shift combination instead of foreach to save memory
+ while (is_array($actionDetails) && count($actionDetails)) {
+ $action = array_shift($actionDetails);
+ $idVisit = $action['idvisit'];
+ unset($action['idvisit']);
+ $actions[$idVisit][] = $action;
+ }
+ }
+
+
+ public function provideActionsForVisit(&$actions, $visitorDetails)
+ {
+ $actionDetails = $actions;
+
+ $formatter = new Formatter();
+
+ $actionTypesToHandle = array(
+ Action::TYPE_PAGE_URL,
+ Action::TYPE_SITE_SEARCH,
+ Action::TYPE_EVENT,
+ Action::TYPE_OUTLINK,
+ Action::TYPE_DOWNLOAD
+ );
+
+ // Enrich with time spent per action
+ $nextActionId = 0;
+ foreach ($actionDetails as $idx => &$action) {
+
+ if ($idx < $nextActionId || !in_array($action['type'], $actionTypesToHandle)) {
+ continue; // skip to next action having timeSpentRef
+ }
+
+ // search for next action with timeSpentRef
+ $nextActionId = $idx + 1;
+ $nextAction = null;
+
+ while (isset($actionDetails[$nextActionId]) &&
+ (!in_array($actionDetails[$nextActionId]['type'], $actionTypesToHandle) ||
+ !array_key_exists('timeSpentRef', $actionDetails[$nextActionId]))) {
+ $nextActionId++;
+ }
+ $nextAction = isset($actionDetails[$nextActionId]) ? $actionDetails[$nextActionId] : null;
+
+ // Set the time spent for this action (which is the timeSpentRef of the next action)
+ if ($nextAction) {
+ $action['timeSpent'] = $nextAction['timeSpentRef'];
+ } else {
+
+ // Last action of a visit.
+ // By default, Piwik does not know how long the user stayed on the page
+ // If enableHeartBeatTimer() is used in piwik.js then we can find the accurate time on page for the last pageview
+ $visitTotalTime = $visitorDetails['visitDuration'];
+ $timeOfLastAction = Date::factory($action['serverTimePretty'])->getTimestamp();
+
+ $timeSpentOnAllActionsApartFromLastOne = ($timeOfLastAction - $visitorDetails['firstActionTimestamp']);
+ $timeSpentOnPage = $visitTotalTime - $timeSpentOnAllActionsApartFromLastOne;
+
+ // Safe net, we assume the time is correct when it's more than 10 seconds
+ if ($timeSpentOnPage > 10) {
+ $action['timeSpent'] = $timeSpentOnPage;
+ }
+ }
+
+ if (isset($action['timeSpent'])) {
+ $action['timeSpentPretty'] = $formatter->getPrettyTimeFromSeconds($action['timeSpent'], true);
+ }
+
+ unset($action['timeSpentRef']); // not needed after timeSpent is added
+ }
+
+ $actions = $actionDetails;
+ }
+
+ public function extendActionDetails(&$action, $nextAction, $visitorDetails)
+ {
+ $formatter = new Formatter();
+
+ if ($action['type'] == Action::TYPE_EVENT) {
+ // Handle Event
+ if (strlen($action['pageTitle']) > 0) {
+ $action['eventName'] = $action['pageTitle'];
+ }
+
+ unset($action['pageTitle']);
+
+ } else {
+ if ($action['type'] == Action::TYPE_SITE_SEARCH) {
+ // Handle Site Search
+ $action['siteSearchKeyword'] = $action['pageTitle'];
+ unset($action['pageTitle']);
+ }
+ }
+
+ // Event value / Generation time
+ if ($action['type'] == Action::TYPE_EVENT) {
+ if (strlen($action['custom_float']) > 0) {
+ $action['eventValue'] = round($action['custom_float'], self::EVENT_VALUE_PRECISION);
+ }
+ } elseif (isset($action['custom_float']) && $action['custom_float'] > 0) {
+ $action['generationTimeMilliseconds'] = $action['custom_float'];
+ $action['generationTime'] = $formatter->getPrettyTimeFromSeconds($action['custom_float'] / 1000, true);
+ }
+ unset($action['custom_float']);
+
+ if ($action['type'] != Action::TYPE_EVENT) {
+ unset($action['eventCategory']);
+ unset($action['eventAction']);
+ }
+
+ if (array_key_exists('interaction_position', $action)) {
+ $action['interactionPosition'] = $action['interaction_position'];
+ unset($action['interaction_position']);
+ }
+
+ // Reconstruct url from prefix
+ if (array_key_exists('url', $action) && array_key_exists('url_prefix', $action)) {
+ $url = PageUrl::reconstructNormalizedUrl($action['url'], $action['url_prefix']);
+ $url = Common::unsanitizeInputValue($url);
+
+ $action['url'] = $url;
+ unset($action['url_prefix']);
+ }
+
+ switch ($action['type']) {
+ case 'goal':
+ $action['icon'] = 'plugins/Morpheus/images/goal.png';
+ break;
+ case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER:
+ case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART:
+ $action['icon'] = 'plugins/Morpheus/images/' . $action['type'] . '.png';
+ break;
+ case Action::TYPE_DOWNLOAD:
+ $action['type'] = 'download';
+ $action['icon'] = 'plugins/Morpheus/images/download.png';
+ break;
+ case Action::TYPE_OUTLINK:
+ $action['type'] = 'outlink';
+ $action['icon'] = 'plugins/Morpheus/images/link.png';
+ break;
+ case Action::TYPE_SITE_SEARCH:
+ $action['type'] = 'search';
+ $action['icon'] = 'plugins/Morpheus/images/search_ico.png';
+ break;
+ case Action::TYPE_PAGE_URL:
+ case '':
+ $action['type'] = 'action';
+ $action['icon'] = null;
+ break;
+ }
+
+ // Convert datetimes to the site timezone
+ $dateTimeVisit = Date::factory($action['serverTimePretty'],
+ Site::getTimezoneFor($visitorDetails['idSite']));
+ $action['serverTimePretty'] = $dateTimeVisit->getLocalized(Date::DATETIME_FORMAT_SHORT);
+ $action['timestamp'] = $dateTimeVisit->getTimestamp();
+
+ unset($action['idlink_va']);
+ }
+
+ /**
+ * @param $idVisit
+ * @return array
+ * @throws \Exception
+ */
+ protected function queryActionsForVisits($idVisits)
+ {
+ $customFields = array();
+ $customJoins = array();
+
+ Piwik::postEvent('Actions.getCustomActionDimensionFieldsAndJoins', array(&$customFields, &$customJoins));
+
+ $customFields = array_filter($customFields);
+ array_unshift($customFields, ''); // add empty element at first
+ $customActionDimensionFields = implode(', ', $customFields);
+
+ // The second join is a LEFT join to allow returning records that don't have a matching page title
+ // eg. Downloads, Outlinks. For these, idaction_name is set to 0
+ $sql = "
+ SELECT
+ log_link_visit_action.idvisit,
+ COALESCE(log_action_event_category.type, log_action.type, log_action_title.type) AS type,
+ log_action.name AS url,
+ log_action.url_prefix,
+ log_action_title.name AS pageTitle,
+ log_action.idaction AS pageIdAction,
+ log_link_visit_action.idpageview,
+ log_link_visit_action.idlink_va,
+ log_link_visit_action.server_time as serverTimePretty,
+ log_link_visit_action.time_spent_ref_action as timeSpentRef,
+ log_link_visit_action.idlink_va AS pageId,
+ log_link_visit_action.custom_float,
+ log_link_visit_action.interaction_position
+ " . $customActionDimensionFields . "
+ FROM " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action
+ LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action
+ ON log_link_visit_action.idaction_url = log_action.idaction
+ LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_title
+ ON log_link_visit_action.idaction_name = log_action_title.idaction
+ " . implode(" ", $customJoins) . "
+ WHERE log_link_visit_action.idvisit IN ('" . implode("','", $idVisits) . "')
+ ORDER BY log_link_visit_action.idvisit, server_time ASC
+ ";
+ $actionDetails = Db::fetchAll($sql);
+ return $actionDetails;
+ }
+
+
+ private $visitedPageUrls = array();
+ private $siteSearchKeywords = array();
+ private $pageGenerationTimeTotal = 0;
+
+ public function initProfile($visits, &$profile)
+ {
+ $this->visitedPageUrls = array();
+ $this->siteSearchKeywords = array();
+ $this->pageGenerationTimeTotal = 0;
+ $profile['totalActions'] = 0;
+ $profile['totalOutlinks'] = 0;
+ $profile['totalDownloads'] = 0;
+ $profile['totalSearches'] = 0;
+ $profile['totalPageViews'] = 0;
+ $profile['totalUniquePageViews'] = 0;
+ $profile['totalRevisitedPages'] = 0;
+ $profile['totalPageViewsWithTiming'] = 0;
+ $profile['searches'] = array();
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ $profile['totalActions'] += $visit->getColumn('actions');
+ }
+
+ public function handleProfileAction($action, &$profile)
+ {
+ $this->handleIfDownloadAction($action, $profile);
+ $this->handleIfOutlinkAction($action, $profile);
+ $this->handleIfSiteSearchAction($action, $profile);
+ $this->handleIfPageViewAction($action, $profile);
+ $this->handleIfPageGenerationTime($action, $profile);
+ }
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ arsort($this->visitedPageUrls);
+ $profile['visitedPages'] = $this->visitedPageUrls;
+
+ $this->handleSiteSearches($profile);
+ $this->handleAveragePageGenerationTime($profile);
+ }
+
+ /**
+ * @param $action
+ */
+ private function handleIfDownloadAction($action, &$profile)
+ {
+ if ($action['type'] != 'download') {
+ return;
+ }
+ $profile['totalDownloads']++;
+ }
+
+ /**
+ * @param $action
+ */
+ private function handleIfOutlinkAction($action, &$profile)
+ {
+ if ($action['type'] != 'outlink') {
+ return;
+ }
+ $profile['totalOutlinks']++;
+ }
+
+ /**
+ * @param $action
+ */
+ private function handleIfPageViewAction($action, &$profile)
+ {
+ if ($action['type'] != 'action') {
+ return;
+ }
+ $profile['totalPageViews']++;
+ $pageUrl = $action['url'];
+ if (!empty($pageUrl)) {
+ if (!array_key_exists($pageUrl, $this->visitedPageUrls)) {
+ $this->visitedPageUrls[$pageUrl] = 0;
+ $profile['totalUniquePageViews']++;
+ }
+ $this->visitedPageUrls[$pageUrl]++;
+ if ($this->visitedPageUrls[$pageUrl] == 2) {
+ $profile['totalRevisitedPages']++;
+ }
+ }
+ }
+
+ private function handleIfSiteSearchAction($action, &$profile)
+ {
+ if (!isset($action['siteSearchKeyword'])) {
+ return;
+ }
+ $keyword = $action['siteSearchKeyword'];
+
+ if (!isset($this->siteSearchKeywords[$keyword])) {
+ $this->siteSearchKeywords[$keyword] = 0;
+ ++$profile['totalSearches'];
+ }
+ ++$this->siteSearchKeywords[$keyword];
+ }
+
+ private function handleSiteSearches(&$profile)
+ {
+ // sort by visit/action
+ arsort($this->siteSearchKeywords);
+
+ foreach ($this->siteSearchKeywords as $keyword => $searchCount) {
+ $profile['searches'][] = array(
+ 'keyword' => $keyword,
+ 'searches' => $searchCount
+ );
+ }
+ }
+
+ private function handleIfPageGenerationTime($action, &$profile)
+ {
+ if (isset($action['generationTimeMilliseconds'])) {
+ $this->pageGenerationTimeTotal += $action['generationTimeMilliseconds'];
+ ++$profile['totalPageViewsWithTiming'];
+ }
+ }
+
+ private function handleAveragePageGenerationTime(&$profile)
+ {
+ if ($profile['totalPageViewsWithTiming']) {
+ $profile['averagePageGenerationTime'] =
+ round($this->pageGenerationTimeTotal / (1000 * $profile['totalPageViewsWithTiming']), $precision = 3);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Actions/lang/en.json b/plugins/Actions/lang/en.json
index 91d219f81b..ab9fbff5f7 100644
--- a/plugins/Actions/lang/en.json
+++ b/plugins/Actions/lang/en.json
@@ -42,7 +42,9 @@
"PagesReportDocumentation": "This report contains information about the page URLs that have been visited. %s The table is organized hierarchically, the URLs are displayed as a folder structure.",
"PageTitlesReportDocumentation": "This report contains information about the titles of the pages that have been visited. %1$s The page title is the HTML %2$s Tag that most browsers show in their window title.",
"PageUrls": "Page URLs",
+ "PageViewsByVisitor": "Number of times this page was viewed by this visitor across all visits",
"PluginDescription": "Reports about the page views and page titles. Lets you measure your internal website's search engine. Automatically tracks clicks on external links and file downloads. ",
+ "RevisitedPages": "Pages viewed more than once",
"SiteSearchCategories1": "This report lists the Categories that visitors selected when they made a Search on your website.",
"SiteSearchCategories2": "For example, Ecommerce websites typically have a \"Category\" selector so that visitors can restrict their searches to all products in a specific Category.",
"SiteSearchFollowingPagesDoc": "When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.",
diff --git a/plugins/Actions/templates/_profileSummary.twig b/plugins/Actions/templates/_profileSummary.twig
new file mode 100644
index 0000000000..fa30e694b8
--- /dev/null
+++ b/plugins/Actions/templates/_profileSummary.twig
@@ -0,0 +1,25 @@
+{% if visitorData.totalPageViews > 0 %}
+ <div class="visitor-profile-summary visitor-profile-pages">
+ <h1>{{ 'Actions_RevisitedPages'|translate }}</h1>
+ <div>
+ <ul>
+ {% for url,count in visitorData.visitedPages %}
+ {% if loop.index < 6 and count > 1 %}
+ <li><span class="repeat icon-refresh" title="{{ 'Actions_PageViewsByVisitor'|translate }}">{{ count }}</span>
+ {% if url|trim|lower starts with 'javascript:' or
+ url|trim|lower starts with 'vbscript:' or
+ url|trim|lower starts with 'data:' %}
+ {{ url }}
+ {% else %}
+ <a href="{{ url }}" rel="noreferrer" target="_blank"
+ class="action-list-url truncated-text-line">
+ {{ url|replace({'http://': '', 'https://': ''}) }}
+ </a>
+ {% endif %}
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+{% endif %} \ No newline at end of file
diff --git a/plugins/Bandwidth b/plugins/Bandwidth
-Subproject de61c39bd84ed3ba5fd5cf638238d097d41fce7
+Subproject 80960c0091e404db1a50d72ef7c064cd38b9033
diff --git a/plugins/Contents/Contents.php b/plugins/Contents/Contents.php
index 99e47bf8fd..289bdb25ec 100644
--- a/plugins/Contents/Contents.php
+++ b/plugins/Contents/Contents.php
@@ -8,6 +8,7 @@
*/
namespace Piwik\Plugins\Contents;
+use Piwik\Common;
use Piwik\Piwik;
class Contents extends \Piwik\Plugin
@@ -21,6 +22,7 @@ class Contents extends \Piwik\Plugin
'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
+ 'Actions.getCustomActionDimensionFieldsAndJoins' => 'provideActionDimensionFields'
);
}
@@ -41,4 +43,20 @@ class Contents extends \Piwik\Plugin
$translations['nb_impressions'] = Piwik::translate('Contents_ImpressionsMetricDocumentation');
$translations['nb_interactions'] = Piwik::translate('Contents_InteractionsMetricDocumentation');
}
+
+ public function provideActionDimensionFields(&$fields, &$joins)
+ {
+ $fields[] = 'log_action_content_name.name as contentName';
+ $fields[] = 'log_action_content_piece.name as contentPiece';
+ $fields[] = 'log_action_content_target.name as contentTarget';
+ $fields[] = 'log_action_content_interaction.name as contentInteraction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_content_name
+ ON log_link_visit_action.idaction_content_name = log_action_content_name.idaction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_content_piece
+ ON log_link_visit_action.idaction_content_piece = log_action_content_piece.idaction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_content_target
+ ON log_link_visit_action.idaction_content_target = log_action_content_target.idaction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_content_interaction
+ ON log_link_visit_action.idaction_content_interaction = log_action_content_interaction.idaction';
+ }
}
diff --git a/plugins/Contents/VisitorDetails.php b/plugins/Contents/VisitorDetails.php
new file mode 100644
index 0000000000..acf3363d38
--- /dev/null
+++ b/plugins/Contents/VisitorDetails.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Contents;
+
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Tracker\Action;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendActionDetails(&$action, $nextAction, $visitorDetails)
+ {
+ if ($action['type'] != Action::TYPE_CONTENT) {
+ unset($action['contentName']);
+ unset($action['contentPiece']);
+ unset($action['contentTarget']);
+ unset($action['contentInteraction']);
+ }
+ }
+
+ public function renderAction($action, $previousAction, $visitorDetails)
+ {
+ if ($action['type'] != Action::TYPE_CONTENT) {
+ return;
+ }
+
+ $view = new View('@Contents/_actionContent.twig');
+ $view->action = $action;
+ $view->previousAction = $previousAction;
+ $view->visitInfo = $visitorDetails;
+ return $view->render();
+ }
+
+ public function renderActionTooltip($action, $visitInfo)
+ {
+ if ($action['type'] != Action::TYPE_CONTENT) {
+ return [];
+ }
+
+ $view = new View('@Contents/_actionTooltip');
+ $view->action = $action;
+ return [[ 10, $view->render() ]];
+ }
+} \ No newline at end of file
diff --git a/plugins/Contents/lang/en.json b/plugins/Contents/lang/en.json
index 915b9d9746..0947590f69 100644
--- a/plugins/Contents/lang/en.json
+++ b/plugins/Contents/lang/en.json
@@ -2,6 +2,7 @@
"Contents": {
"PluginDescription": "Content and banner tracking lets you measure the performance (views, clicks, CTR) of any piece of content on your pages (Banner ad, image, any item).",
"Impressions": "Impressions",
+ "ContentImpression": "Content Impression",
"ContentInteraction": "Content Interaction",
"ContentInteractions": "Content Interactions",
"InteractionRate": "Interaction Rate",
diff --git a/plugins/Contents/templates/_actionContent.twig b/plugins/Contents/templates/_actionContent.twig
new file mode 100644
index 0000000000..138f0e350e
--- /dev/null
+++ b/plugins/Contents/templates/_actionContent.twig
@@ -0,0 +1,15 @@
+<li class="content"
+ title="{{ postEvent('Live.renderActionTooltip', action, visitInfo) }}">
+ <div>
+ {% if action.contentInteraction %}
+ <span class="icon-document action-list-action-icon" title="{{ 'Contents_ContentInteraction'|translate }}"></span>
+ {% else %}
+ <span class="icon-show action-list-action-icon" title="{{ 'Contents_ContentImpression'|translate }}"></span>
+ {% endif %}
+ {% if action.contentInteraction %}
+ [{{ action.contentInteraction }}]
+ {% endif %}
+ {{ action.contentName }} -
+ {{ action.contentPiece }}
+ </div>
+</li>
diff --git a/plugins/Contents/templates/_actionTooltip.twig b/plugins/Contents/templates/_actionTooltip.twig
new file mode 100644
index 0000000000..c81c6883b4
--- /dev/null
+++ b/plugins/Contents/templates/_actionTooltip.twig
@@ -0,0 +1,9 @@
+{% if action.contentName %}
+
+{{ 'Contents_ContentName'|translate }}: {{ action.contentName }}{% endif %}{% if action.contentPiece %}
+
+{{ 'Contents_ContentPiece'|translate }}: {{ action.contentPiece }}{% endif %}{% if action.contentTarget %}
+
+{{ 'Contents_ContentTarget'|translate }}: {{ action.contentTarget }}{% endif %}{% if action.contentInteraction %}
+
+{{ 'Contents_ContentInteraction'|translate }}: {{ action.contentInteraction }}{% endif %} \ No newline at end of file
diff --git a/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml
index 24930328ff..52061fb273 100644
--- a/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml
@@ -12,14 +12,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>2</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>3</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>4</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>5</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>6</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>7</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>8</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>9</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>10</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>11</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>12</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -71,6 +272,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -104,17 +311,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -128,14 +324,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>14</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>15</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>16</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>17</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>18</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>19</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>20</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>21</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>22</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>23</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>24</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -187,6 +584,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -216,16 +619,5 @@
<pluginName>director</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml
index 24930328ff..52061fb273 100644
--- a/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml
@@ -12,14 +12,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>2</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>3</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>4</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>5</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>6</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>7</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>8</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>9</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>10</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>11</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>12</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -71,6 +272,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -104,17 +311,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -128,14 +324,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>14</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>15</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>16</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>17</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>18</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>19</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>20</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>21</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>22</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>23</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>24</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -187,6 +584,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -216,16 +619,5 @@
<pluginName>director</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
index 24930328ff..52061fb273 100644
--- a/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
@@ -12,14 +12,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>2</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>3</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>4</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>5</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>6</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>7</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>8</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>9</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>10</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>11</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>12</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -71,6 +272,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -104,17 +311,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -128,14 +324,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>14</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>15</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>16</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>17</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>18</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>19</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>20</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>21</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>22</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>23</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>24</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -187,6 +584,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -216,16 +619,5 @@
<pluginName>director</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
index 24930328ff..52061fb273 100644
--- a/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
@@ -12,14 +12,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>2</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>3</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>4</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>5</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>6</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>7</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>8</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>9</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>10</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>11</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>12</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -71,6 +272,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -104,17 +311,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -128,14 +324,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>14</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>15</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>16</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>17</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>18</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>19</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>20</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>21</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>22</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>23</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>24</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -187,6 +584,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -216,16 +619,5 @@
<pluginName>director</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
index 24930328ff..52061fb273 100644
--- a/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
@@ -12,14 +12,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>2</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>3</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>4</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>5</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>6</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>7</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>8</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>9</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>10</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>11</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>12</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -71,6 +272,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -104,17 +311,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -128,14 +324,215 @@
<pageTitle>Ads</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
+ <timeSpent>271</timeSpent>
+ <timeSpentPretty>4 min 31s</timeSpentPretty>
<generationTimeMilliseconds>333</generationTimeMilliseconds>
<generationTime>0.33s</generationTime>
<interactionPosition>1</interactionPosition>
- <timeSpent>271</timeSpent>
- <timeSpentPretty>4 min 31s</timeSpentPretty>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>14</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>Unknown</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>15</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece />
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>120</timeSpentRef>
+ <pageId>16</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>17</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad2.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>18</pageId>
+ <contentName>ImageAd</contentName>
+ <contentPiece>/path/ad.jpg</contentPiece>
+ <contentTarget>http://www.example.com</contentTarget>
+ <contentInteraction>submit</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>19</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>20</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/</contentTarget>
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>21</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>0</timeSpentRef>
+ <pageId>22</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click NOW</contentPiece>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ <contentInteraction>click</contentInteraction>
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>60</timeSpentRef>
+ <pageId>23</pageId>
+ <contentName>Text Ad</contentName>
+ <contentPiece>Click to download Piwik now</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
+ </row>
+ <row>
+ <type>13</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle />
+ <pageIdAction>3</pageIdAction>
+
+
+ <timeSpentRef>30</timeSpentRef>
+ <pageId>24</pageId>
+ <contentName>Video Ad</contentName>
+ <contentPiece>movie.mov</contentPiece>
+ <contentTarget />
+ <contentInteraction />
+ <bandwidth />
+ <interactionPosition />
+
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -187,6 +584,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -216,16 +619,5 @@
<pluginName>director</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php
index fd3e729f74..be56c144f8 100644
--- a/plugins/CoreHome/CoreHome.php
+++ b/plugins/CoreHome/CoreHome.php
@@ -30,7 +30,6 @@ class CoreHome extends \Piwik\Plugin
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.filterMergedJavaScripts' => 'filterMergedJavaScripts',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
);
}
@@ -39,25 +38,6 @@ class CoreHome extends \Piwik\Plugin
$mergedContent = preg_replace('/(sourceMappingURL=(.*?).map)/', '', $mergedContent);
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['userId'] = $instance->getUserId();
- $visitor['visitorType'] = $instance->getVisitorReturning();
- $visitor['visitorTypeIcon'] = $instance->getVisitorReturningIcon();
- $visitor['visitConverted'] = $instance->isVisitorGoalConverted();
- $visitor['visitConvertedIcon'] = $instance->getVisitorGoalConvertedIcon();
- $visitor['visitCount'] = $instance->getVisitCount();
- $visitor['firstActionTimestamp'] = $instance->getTimestampFirstAction();
- $visitor['visitEcommerceStatus'] = $instance->getVisitEcommerceStatus();
- $visitor['visitEcommerceStatusIcon'] = $instance->getVisitEcommerceStatusIcon();
- $visitor['daysSinceFirstVisit'] = $instance->getDaysSinceFirstVisit();
- $visitor['daysSinceLastEcommerceOrder'] = $instance->getDaysSinceLastEcommerceOrder();
- $visitor['visitDuration'] = $instance->getVisitLength();
- $visitor['visitDurationPretty'] = $instance->getVisitLengthPretty();
- }
-
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "libs/jquery/themes/base/jquery-ui.min.css";
diff --git a/plugins/CoreHome/Visitor.php b/plugins/CoreHome/Visitor.php
deleted file mode 100644
index 962eabce31..0000000000
--- a/plugins/CoreHome/Visitor.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\CoreHome;
-
-use Piwik\Metrics\Formatter;
-use Piwik\Plugins\CoreHome\Columns\VisitGoalBuyer;
-
-class Visitor
-{
- private $details = array();
- private $metricsFormatter = null;
-
- public function __construct($details)
- {
- $this->details = $details;
- $this->metricsFormatter = new Formatter();
- }
-
- function getTimestampFirstAction()
- {
- return strtotime($this->details['visit_first_action_time']);
- }
-
- function getVisitEcommerceStatusIcon()
- {
- $status = $this->getVisitEcommerceStatus();
-
- if (in_array($status, array('ordered', 'orderedThenAbandonedCart'))) {
- return "plugins/Morpheus/images/ecommerceOrder.png";
- } elseif ($status == 'abandonedCart') {
- return "plugins/Morpheus/images/ecommerceAbandonedCart.png";
- }
- // Note: it is important that there is no icon when there was no ecommerce conversion
- return null;
- }
-
- function getVisitEcommerceStatus()
- {
- return VisitGoalBuyer::getVisitEcommerceStatusFromId($this->details['visit_goal_buyer']);
- }
-
- function isVisitorGoalConverted()
- {
- return $this->details['visit_goal_converted'];
- }
-
- function getVisitorGoalConvertedIcon()
- {
- return $this->isVisitorGoalConverted()
- ? "plugins/Morpheus/images/goal.png"
- : null;
- }
-
- function getDaysSinceFirstVisit()
- {
- return $this->details['visitor_days_since_first'];
- }
-
- function getDaysSinceLastEcommerceOrder()
- {
- return $this->details['visitor_days_since_order'];
- }
-
- function getVisitorReturning()
- {
- $type = $this->details['visitor_returning'];
- return $type == 2
- ? 'returningCustomer'
- : ($type == 1
- ? 'returning'
- : 'new');
- }
-
- function getVisitorReturningIcon()
- {
- $type = $this->getVisitorReturning();
- if ($type == 'returning'
- || $type == 'returningCustomer'
- ) {
- return "plugins/Live/images/returningVisitor.png";
- }
- return null;
- }
-
- function getVisitCount()
- {
- return $this->details['visitor_count_visits'];
- }
-
- function getVisitLength()
- {
- return $this->details['visit_total_time'];
- }
-
- function getVisitLengthPretty()
- {
- return $this->metricsFormatter->getPrettyTimeFromSeconds($this->details['visit_total_time'], true);
- }
-
- function getUserId()
- {
- if (isset($this->details['user_id'])
- && strlen($this->details['user_id']) > 0) {
- return $this->details['user_id'];
- }
- return null;
- }
-} \ No newline at end of file
diff --git a/plugins/CoreHome/VisitorDetails.php b/plugins/CoreHome/VisitorDetails.php
new file mode 100644
index 0000000000..88ae63a09c
--- /dev/null
+++ b/plugins/CoreHome/VisitorDetails.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome;
+
+use Piwik\Metrics\Formatter;
+use Piwik\Plugins\CoreHome\Columns\VisitGoalBuyer;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['userId'] = $this->getUserId();
+ $visitor['visitorType'] = $this->getVisitorReturning();
+ $visitor['visitorTypeIcon'] = $this->getVisitorReturningIcon();
+ $visitor['visitConverted'] = $this->isVisitorGoalConverted();
+ $visitor['visitConvertedIcon'] = $this->getVisitorGoalConvertedIcon();
+ $visitor['visitCount'] = $this->getVisitCount();
+ $visitor['visitEcommerceStatus'] = $this->getVisitEcommerceStatus();
+ $visitor['visitEcommerceStatusIcon'] = $this->getVisitEcommerceStatusIcon();
+ $visitor['daysSinceFirstVisit'] = $this->getDaysSinceFirstVisit();
+ $visitor['daysSinceLastEcommerceOrder'] = $this->getDaysSinceLastEcommerceOrder();
+ $visitor['visitDuration'] = $this->getVisitLength();
+ $visitor['visitDurationPretty'] = $this->getVisitLengthPretty();
+ }
+
+ protected function getVisitEcommerceStatusIcon()
+ {
+ $status = $this->getVisitEcommerceStatus();
+
+ if (in_array($status, array('ordered', 'orderedThenAbandonedCart'))) {
+ return "plugins/Morpheus/images/ecommerceOrder.png";
+ } elseif ($status == 'abandonedCart') {
+ return "plugins/Morpheus/images/ecommerceAbandonedCart.png";
+ }
+ // Note: it is important that there is no icon when there was no ecommerce conversion
+ return null;
+ }
+
+ protected function getVisitEcommerceStatus()
+ {
+ return VisitGoalBuyer::getVisitEcommerceStatusFromId($this->details['visit_goal_buyer']);
+ }
+
+ protected function isVisitorGoalConverted()
+ {
+ return $this->details['visit_goal_converted'];
+ }
+
+ protected function getVisitorGoalConvertedIcon()
+ {
+ return $this->isVisitorGoalConverted()
+ ? "plugins/Morpheus/images/goal.png"
+ : null;
+ }
+
+ protected function getDaysSinceFirstVisit()
+ {
+ return $this->details['visitor_days_since_first'];
+ }
+
+ protected function getDaysSinceLastEcommerceOrder()
+ {
+ return $this->details['visitor_days_since_order'];
+ }
+
+ protected function getVisitorReturning()
+ {
+ $type = $this->details['visitor_returning'];
+ return $type == 2
+ ? 'returningCustomer'
+ : ($type == 1
+ ? 'returning'
+ : 'new');
+ }
+
+ protected function getVisitorReturningIcon()
+ {
+ $type = $this->getVisitorReturning();
+ if ($type == 'returning'
+ || $type == 'returningCustomer'
+ ) {
+ return "plugins/Live/images/returningVisitor.png";
+ }
+ return null;
+ }
+
+ protected function getVisitCount()
+ {
+ return $this->details['visitor_count_visits'];
+ }
+
+ protected function getVisitLength()
+ {
+ return $this->details['visit_total_time'];
+ }
+
+ protected function getVisitLengthPretty()
+ {
+ $formatter = new Formatter();
+ return $formatter->getPrettyTimeFromSeconds($this->details['visit_total_time'], true);
+ }
+
+ protected function getUserId()
+ {
+ if (isset($this->details['user_id'])
+ && strlen($this->details['user_id']) > 0
+ ) {
+ return $this->details['user_id'];
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
-Subproject 122175590067b87b04010e928a35e85e9c011e2
+Subproject 5679c533d3686b8df955f156d259c3d90fe2f80
diff --git a/plugins/CustomVariables/CustomVariables.php b/plugins/CustomVariables/CustomVariables.php
index 78a779e5f9..e5a13bc52a 100644
--- a/plugins/CustomVariables/CustomVariables.php
+++ b/plugins/CustomVariables/CustomVariables.php
@@ -20,10 +20,10 @@ class CustomVariables extends \Piwik\Plugin
public function registerEvents()
{
return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
+ 'Actions.getCustomActionDimensionFieldsAndJoins' => 'provideActionDimensionFields'
);
}
@@ -37,24 +37,6 @@ class CustomVariables extends \Piwik\Plugin
Model::uninstall();
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $customVariables = array();
-
- $maxCustomVariables = self::getNumUsableCustomVariables();
-
- for ($i = 1; $i <= $maxCustomVariables; $i++) {
- if (!empty($details['custom_var_k' . $i])) {
- $customVariables[$i] = array(
- 'customVariableName' . $i => $details['custom_var_k' . $i],
- 'customVariableValue' . $i => $details['custom_var_v' . $i],
- );
- }
- }
-
- $visitor['customVariables'] = $customVariables;
- }
-
/**
* There are also some hardcoded places in JavaScript
* @return int
@@ -136,4 +118,13 @@ class CustomVariables extends \Piwik\Plugin
$jsFiles[] = "plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.js";
}
+ public function provideActionDimensionFields(&$fields, &$joins)
+ {
+ $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
+ $fields[] = 'custom_var_k' . $i;
+ $fields[] = 'custom_var_v' . $i;
+ }
+ }
}
diff --git a/plugins/CustomVariables/ProfileSummary/VisitScopeSummary.php b/plugins/CustomVariables/ProfileSummary/VisitScopeSummary.php
new file mode 100644
index 0000000000..8bab78187e
--- /dev/null
+++ b/plugins/CustomVariables/ProfileSummary/VisitScopeSummary.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\CustomVariables\ProfileSummary;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugins\CustomVariables\Model;
+use Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract;
+use Piwik\View;
+
+/**
+ * Class VisitScopeSummary
+ *
+ * @api
+ */
+class VisitScopeSummary extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('CustomVariables_CustomVariables') . ' ' . Piwik::translate('General_TrackingScopeVisit');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ if (empty($this->profile['customVariables']) || empty($this->profile['customVariables'][Model::SCOPE_VISIT])) {
+ return '';
+ }
+
+ $view = new View('@CustomVariables/_profileSummary.twig');
+ $view->visitorData = $this->profile;
+ $view->scopeName = Piwik::translate('General_TrackingScopeVisit');
+ $view->variables = $this->profile['customVariables'][Model::SCOPE_VISIT];
+ return $view->render();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 15;
+ }
+} \ No newline at end of file
diff --git a/plugins/CustomVariables/VisitorDetails.php b/plugins/CustomVariables/VisitorDetails.php
new file mode 100644
index 0000000000..e90af8e3c1
--- /dev/null
+++ b/plugins/CustomVariables/VisitorDetails.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CustomVariables;
+
+use Piwik\Piwik;
+use Piwik\Plugins\Actions\Actions\ActionSiteSearch;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $customVariables = array();
+
+ $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
+ if (!empty($this->details['custom_var_k' . $i])) {
+ $customVariables[$i] = array(
+ 'customVariableName' . $i => $this->details['custom_var_k' . $i],
+ 'customVariableValue' . $i => $this->details['custom_var_v' . $i],
+ );
+ }
+ }
+
+ $visitor['customVariables'] = $customVariables;
+ }
+
+ public function extendActionDetails(&$action, $nextAction, $visitorDetails)
+ {
+ $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
+ $customVariablesPage = array();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
+ if (!empty($action['custom_var_k' . $i])) {
+ $cvarKey = $action['custom_var_k' . $i];
+ $cvarKey = static::getCustomVariablePrettyKey($cvarKey);
+ $customVariablesPage[$i] = array(
+ 'customVariablePageName' . $i => $cvarKey,
+ 'customVariablePageValue' . $i => $action['custom_var_v' . $i],
+ );
+ }
+ unset($action['custom_var_k' . $i]);
+ unset($action['custom_var_v' . $i]);
+ }
+ if (!empty($customVariablesPage)) {
+ $action['customVariables'] = $customVariablesPage;
+ }
+ }
+
+ public function renderActionTooltip($action, $visitInfo)
+ {
+ if (empty($action['customVariables'])) {
+ return [];
+ }
+
+ $view = new View('@CustomVariables/_actionTooltip');
+ $view->action = $action;
+ return [[ 40, $view->render() ]];
+ }
+
+ public function renderVisitorDetails($visitInfo)
+ {
+ $view = new View('@CustomVariables/_visitorDetails');
+ $view->visitInfo = $visitInfo;
+ return [[ 50, $view->render() ]];
+ }
+
+ private static function getCustomVariablePrettyKey($key)
+ {
+ $rename = array(
+ ActionSiteSearch::CVAR_KEY_SEARCH_CATEGORY => Piwik::translate('Actions_ColumnSearchCategory'),
+ ActionSiteSearch::CVAR_KEY_SEARCH_COUNT => Piwik::translate('Actions_ColumnSearchResultsCount'),
+ );
+ if (isset($rename[$key])) {
+ return $rename[$key];
+ }
+ return $key;
+ }
+
+
+ protected $customVariables = [];
+
+ public function initProfile($visits, &$profile)
+ {
+ $this->customVariables = [
+ Model::SCOPE_PAGE => [],
+ Model::SCOPE_VISIT => [],
+ ];
+ }
+
+ public function handleProfileAction($action, &$profile)
+ {
+ if (empty($action['customVariables'])) {
+ return;
+ }
+
+ foreach ($action['customVariables'] as $index => $customVariable) {
+
+ $scope = Model::SCOPE_PAGE;
+ $name = $customVariable['customVariablePageName'.$index];
+ $value = $customVariable['customVariablePageValue'.$index];
+
+ if (empty($value)) {
+ continue;
+ }
+
+ if (!array_key_exists($name, $this->customVariables[$scope])) {
+ $this->customVariables[$scope][$name] = [];
+ }
+
+ if (!array_key_exists($value, $this->customVariables[$scope][$name])) {
+ $this->customVariables[$scope][$name][$value] = 0;
+ }
+
+ $this->customVariables[$scope][$name][$value]++;
+ }
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ if (empty($visit['customVariables'])) {
+ return;
+ }
+
+ foreach ($visit['customVariables'] as $index => $customVariable) {
+
+ $scope = Model::SCOPE_VISIT;
+ $name = $customVariable['customVariableName'.$index];
+ $value = $customVariable['customVariableValue'.$index];
+
+ if (empty($value)) {
+ continue;
+ }
+
+ if (!array_key_exists($name, $this->customVariables[$scope])) {
+ $this->customVariables[$scope][$name] = [];
+ }
+
+ if (!array_key_exists($value, $this->customVariables[$scope][$name])) {
+ $this->customVariables[$scope][$name][$value] = 0;
+ }
+
+ $this->customVariables[$scope][$name][$value]++;
+ }
+ }
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ $customVariables = $this->customVariables;
+ foreach ($customVariables as $scope => &$variables) {
+
+ if (empty($variables)) {
+ unset($customVariables[$scope]);
+ continue;
+ }
+
+ foreach ($variables AS $name => &$values) {
+ arsort($values);
+ }
+ }
+ if (!empty($customVariables)) {
+
+ $profile['customVariables'] = $this->convertForProfile($customVariables);
+ }
+ }
+
+ protected function convertForProfile($customVariables)
+ {
+ $convertedVariables = [];
+
+ foreach ($customVariables as $scope => $scopeVariables) {
+
+ $convertedVariables[$scope] = [];
+
+ foreach ($scopeVariables as $name => $values) {
+
+ $variable = [
+ 'name' => $name,
+ 'values' => []
+ ];
+
+ foreach ($values as $value => $count) {
+ $variable['values'][] = [
+ 'value' => $value,
+ 'count' => $count
+ ];
+ }
+
+ $convertedVariables[$scope][] = $variable;
+ }
+ }
+
+ return $convertedVariables;
+ }
+} \ No newline at end of file
diff --git a/plugins/CustomVariables/templates/_actionTooltip.twig b/plugins/CustomVariables/templates/_actionTooltip.twig
new file mode 100644
index 0000000000..52084a4be5
--- /dev/null
+++ b/plugins/CustomVariables/templates/_actionTooltip.twig
@@ -0,0 +1,10 @@
+{% if action.customVariables is defined %}
+
+ {{ 'CustomVariables_CustomVariables'|translate }}:{% for id,customVariable in action.customVariables %}
+ {% set name = 'customVariablePageName' ~ id %}
+ {% set value = 'customVariablePageValue' ~ id %}
+
+ {# line break above is important #}
+ - {{ customVariable[name]|raw }} {% if customVariable[value]|length > 0 %} = {{ customVariable[value]|raw }}{% endif %}
+ {% endfor %}
+{% endif -%} \ No newline at end of file
diff --git a/plugins/CustomVariables/templates/_profileSummary.twig b/plugins/CustomVariables/templates/_profileSummary.twig
new file mode 100644
index 0000000000..3540faf5c6
--- /dev/null
+++ b/plugins/CustomVariables/templates/_profileSummary.twig
@@ -0,0 +1,13 @@
+<div class="visitor-profile-summary visitor-profile-customvariables">
+ <h1>{{ 'CustomVariables_CustomVariables'|translate }} ({{ scopeName }})</h1>
+ <div>
+ {%- for variable in variables -%}
+ <p>
+ <span>{{ variable.name }}: </span>
+ {%- for value in variable.values -%}
+ <strong title="{{ value.count }}x">{{ value.value }}</strong>{% if not loop.last %}, {% endif %}
+ {%- endfor -%}
+ </p>
+ {%- endfor -%}
+ </div>
+</div>
diff --git a/plugins/CustomVariables/templates/_visitorDetails.twig b/plugins/CustomVariables/templates/_visitorDetails.twig
new file mode 100644
index 0000000000..df26da450d
--- /dev/null
+++ b/plugins/CustomVariables/templates/_visitorDetails.twig
@@ -0,0 +1,13 @@
+{% if visitInfo.getColumn('customVariables') %}
+ <div class="visitorCustomVariables">
+ {% for id,customVariable in visitInfo.getColumn('customVariables') %}
+ {% set name='customVariableName' ~ id %}
+ {% set value='customVariableValue' ~ id %}
+ <br/>
+ <abbr class="visitorLogTooltip" title="{{ 'CustomVariables_CustomVariables'|translate }} ({{ 'CustomVariables_Index'|translate }} {{ id }})">
+ {{ customVariable[name]|truncate(30) }}
+ </abbr>
+ {% if customVariable[value]|length > 0 %}: {{ customVariable[value]|truncate(50) }}{% endif %}
+ {% endfor %}
+ </div>
+{% endif %} \ No newline at end of file
diff --git a/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
index a9d67a0691..5357171fef 100644
--- a/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
+++ b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
@@ -23,7 +23,12 @@
<pageTitle>Profile page</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>1</pageId>
+ <bandwidth />
+ <interactionPosition>1</interactionPosition>
+ <icon />
+
<customVariables>
<row>
<customVariablePageName1>Name_PAGE_1</customVariablePageName1>
@@ -58,9 +63,7 @@
<customVariablePageValue8>Val_PAGE8</customVariablePageValue8>
</row>
</customVariables>
- <interactionPosition>1</interactionPosition>
- <icon />
-
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>1</goalConversions>
@@ -91,7 +94,7 @@
<referrerName>Google</referrerName>
<referrerKeyword>this keyword should be ranked</referrerKeyword>
<referrerKeywordPosition>1</referrerKeywordPosition>
- <referrerUrl>http://www.google.com/search?q=this+keyword+should+be+ranked</referrerUrl>
+ <referrerUrl>http://www.google.com/url?sa=t&amp;source=web&amp;cd=1&amp;ved=0CB4QFjAA&amp;url=http://piwik.org/&amp;rct=j&amp;q=this keyword should be ranked&amp;ei=V8WfTePkKKLfiALrpZWGAw&amp;usg=AFQjCNF_MGJRqKPvaKuUokHtZ3VvNG9ALw&amp;sig2=BvKAdCtNixsmfNWXjsNyMw</referrerUrl>
<referrerSearchEngineUrl>http://google.com</referrerSearchEngineUrl>
<referrerSearchEngineIcon>plugins/Morpheus/icons/dist/searchEngines/google.com.png</referrerSearchEngineIcon>
<languageCode>fr</languageCode>
@@ -112,6 +115,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/FF.png</browserIcon>
<browserCode>FF</browserCode>
<browserVersion>3.6</browserVersion>
+ <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Europe</continent>
<continentCode>eur</continentCode>
@@ -177,16 +186,5 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</result> \ No newline at end of file
diff --git a/plugins/DevicePlugins/DevicePlugins.php b/plugins/DevicePlugins/DevicePlugins.php
index fdf91ff464..2d7bab595f 100644
--- a/plugins/DevicePlugins/DevicePlugins.php
+++ b/plugins/DevicePlugins/DevicePlugins.php
@@ -25,18 +25,9 @@ class DevicePlugins extends \Piwik\Plugin
{
return array(
'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
);
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['plugins'] = $instance->getPlugins();
- $visitor['pluginsIcons'] = $instance->getPluginIcons();
- }
-
public function addMetricTranslations(&$translations)
{
$metrics = array(
diff --git a/plugins/DevicePlugins/Visitor.php b/plugins/DevicePlugins/VisitorDetails.php
index d254265974..04620c0e31 100644
--- a/plugins/DevicePlugins/Visitor.php
+++ b/plugins/DevicePlugins/VisitorDetails.php
@@ -2,26 +2,27 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\DevicePlugins;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+
require_once PIWIK_INCLUDE_PATH . '/plugins/DevicePlugins/functions.php';
-class Visitor
+class VisitorDetails extends VisitorDetailsAbstract
{
const DELIMITER_PLUGIN_NAME = ", ";
- private $details = array();
-
- public function __construct($details)
+ public function extendVisitorDetails(&$visitor)
{
- $this->details = $details;
+ $visitor['plugins'] = $this->getPlugins();
+ $visitor['pluginsIcons'] = $this->getPluginIcons();
}
- function getPlugins()
+ protected function getPlugins()
{
$plugins = array();
$columns = DevicePlugins::getAllPluginColumns();
@@ -42,7 +43,7 @@ class Visitor
return implode(self::DELIMITER_PLUGIN_NAME, $pluginShortNames);
}
- function getPluginIcons()
+ protected function getPluginIcons()
{
$pluginNames = $this->getPlugins();
if (!empty($pluginNames)) {
diff --git a/plugins/DevicesDetection/DevicesDetection.php b/plugins/DevicesDetection/DevicesDetection.php
index 2a3f074017..ab36c9fe2d 100644
--- a/plugins/DevicesDetection/DevicesDetection.php
+++ b/plugins/DevicesDetection/DevicesDetection.php
@@ -9,42 +9,8 @@
namespace Piwik\Plugins\DevicesDetection;
-use Piwik\ArchiveProcessor;
-use Piwik\Db;
-
require_once PIWIK_INCLUDE_PATH . '/plugins/DevicesDetection/functions.php';
class DevicesDetection extends \Piwik\Plugin
{
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
- );
- }
-
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['deviceType'] = $instance->getDeviceType();
- $visitor['deviceTypeIcon'] = $instance->getDeviceTypeIcon();
- $visitor['deviceBrand'] = $instance->getDeviceBrand();
- $visitor['deviceModel'] = $instance->getDeviceModel();
- $visitor['operatingSystem'] = $instance->getOperatingSystem();
- $visitor['operatingSystemName'] = $instance->getOperatingSystemName();
- $visitor['operatingSystemIcon'] = $instance->getOperatingSystemIcon();
- $visitor['operatingSystemCode'] = $instance->getOperatingSystemCode();
- $visitor['operatingSystemVersion'] = $instance->getOperatingSystemVersion();
- $visitor['browserFamily'] = $instance->getBrowserEngine();
- $visitor['browserFamilyDescription'] = $instance->getBrowserEngineDescription();
- $visitor['browser'] = $instance->getBrowser();
- $visitor['browserName'] = $instance->getBrowserName();
- $visitor['browserIcon'] = $instance->getBrowserIcon();
- $visitor['browserCode'] = $instance->getBrowserCode();
- $visitor['browserVersion'] = $instance->getBrowserVersion();
- }
}
diff --git a/plugins/DevicesDetection/ProfileSummary/DevicesSummary.php b/plugins/DevicesDetection/ProfileSummary/DevicesSummary.php
new file mode 100644
index 0000000000..7d61784cf1
--- /dev/null
+++ b/plugins/DevicesDetection/ProfileSummary/DevicesSummary.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\DevicesDetection\ProfileSummary;
+
+use Piwik\Piwik;
+use Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract;
+use Piwik\View;
+
+/**
+ * Class DevicesSummary
+ *
+ * @api
+ */
+class DevicesSummary extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('DevicesDetection_Devices');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ if (empty($this->profile['devices'])) {
+ return '';
+ }
+
+ $view = new View('@DevicesDetection/_profileSummary.twig');
+ $view->visitorData = $this->profile;
+ return $view->render();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 50;
+ }
+} \ No newline at end of file
diff --git a/plugins/DevicesDetection/Visitor.php b/plugins/DevicesDetection/Visitor.php
deleted file mode 100644
index af05191995..0000000000
--- a/plugins/DevicesDetection/Visitor.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\DevicesDetection;
-
-require_once PIWIK_INCLUDE_PATH . '/plugins/DevicesDetection/functions.php';
-
-class Visitor
-{
- private $details = array();
-
- public function __construct($details)
- {
- $this->details = $details;
- }
-
- public function getDeviceType()
- {
- return getDeviceTypeLabel($this->details['config_device_type']);
- }
-
- public function getDeviceTypeIcon()
- {
- return getDeviceTypeLogo($this->details['config_device_type']);
- }
-
- public function getDeviceBrand()
- {
- return getDeviceBrandLabel($this->details['config_device_brand']);
- }
-
- public function getDeviceModel()
- {
- return $this->details['config_device_model'];
- }
-
- public function getOperatingSystemCode()
- {
- return $this->details['config_os'];
- }
-
- public function getOperatingSystem()
- {
- return getOsFullName($this->details['config_os'] . ";" . $this->details['config_os_version']);
- }
-
- public function getOperatingSystemName()
- {
- return getOsFullName($this->details['config_os']);
- }
-
- public function getOperatingSystemVersion()
- {
- return $this->details['config_os_version'];
- }
-
- public function getOperatingSystemIcon()
- {
- return getOsLogo($this->details['config_os']);
- }
-
- public function getBrowserEngineDescription()
- {
- return getBrowserEngineName($this->getBrowserEngine());
- }
-
- public function getBrowserEngine()
- {
- return $this->details['config_browser_engine'];
- }
-
- public function getBrowserCode()
- {
- return $this->details['config_browser_name'];
- }
-
- public function getBrowserVersion()
- {
- return $this->details['config_browser_version'];
- }
-
- public function getBrowser()
- {
- return getBrowserNameWithVersion($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
- }
-
- public function getBrowserName()
- {
- return getBrowserName($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
- }
-
- public function getBrowserIcon()
- {
- return getBrowserLogo($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
- }
-} \ No newline at end of file
diff --git a/plugins/DevicesDetection/VisitorDetails.php b/plugins/DevicesDetection/VisitorDetails.php
new file mode 100644
index 0000000000..d358c2d1ef
--- /dev/null
+++ b/plugins/DevicesDetection/VisitorDetails.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\DevicesDetection;
+
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\View;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/DevicesDetection/functions.php';
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['deviceType'] = $this->getDeviceType();
+ $visitor['deviceTypeIcon'] = $this->getDeviceTypeIcon();
+ $visitor['deviceBrand'] = $this->getDeviceBrand();
+ $visitor['deviceModel'] = $this->getDeviceModel();
+ $visitor['operatingSystem'] = $this->getOperatingSystem();
+ $visitor['operatingSystemName'] = $this->getOperatingSystemName();
+ $visitor['operatingSystemIcon'] = $this->getOperatingSystemIcon();
+ $visitor['operatingSystemCode'] = $this->getOperatingSystemCode();
+ $visitor['operatingSystemVersion'] = $this->getOperatingSystemVersion();
+ $visitor['browserFamily'] = $this->getBrowserEngine();
+ $visitor['browserFamilyDescription'] = $this->getBrowserEngineDescription();
+ $visitor['browser'] = $this->getBrowser();
+ $visitor['browserName'] = $this->getBrowserName();
+ $visitor['browserIcon'] = $this->getBrowserIcon();
+ $visitor['browserCode'] = $this->getBrowserCode();
+ $visitor['browserVersion'] = $this->getBrowserVersion();
+ }
+
+ protected function getDeviceType()
+ {
+ return getDeviceTypeLabel($this->details['config_device_type']);
+ }
+
+ protected function getDeviceTypeIcon()
+ {
+ return getDeviceTypeLogo($this->details['config_device_type']);
+ }
+
+ protected function getDeviceBrand()
+ {
+ return getDeviceBrandLabel($this->details['config_device_brand']);
+ }
+
+ protected function getDeviceModel()
+ {
+ return $this->details['config_device_model'];
+ }
+
+ protected function getOperatingSystemCode()
+ {
+ return $this->details['config_os'];
+ }
+
+ protected function getOperatingSystem()
+ {
+ return getOsFullName($this->details['config_os'] . ";" . $this->details['config_os_version']);
+ }
+
+ protected function getOperatingSystemName()
+ {
+ return getOsFullName($this->details['config_os']);
+ }
+
+ protected function getOperatingSystemVersion()
+ {
+ return $this->details['config_os_version'];
+ }
+
+ protected function getOperatingSystemIcon()
+ {
+ return getOsLogo($this->details['config_os']);
+ }
+
+ protected function getBrowserEngineDescription()
+ {
+ return getBrowserEngineName($this->getBrowserEngine());
+ }
+
+ protected function getBrowserEngine()
+ {
+ return $this->details['config_browser_engine'];
+ }
+
+ protected function getBrowserCode()
+ {
+ return $this->details['config_browser_name'];
+ }
+
+ protected function getBrowserVersion()
+ {
+ return $this->details['config_browser_version'];
+ }
+
+ protected function getBrowser()
+ {
+ return getBrowserNameWithVersion($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
+ }
+
+ protected function getBrowserName()
+ {
+ return getBrowserName($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
+ }
+
+ protected function getBrowserIcon()
+ {
+ return getBrowserLogo($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
+ }
+
+
+ private $devices = array();
+
+ public function initProfile($visits, &$profile)
+ {
+ $this->devices = array();
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ $deviceType = $visit->getColumn('deviceType');
+ $deviceTypeIcon = $visit->getColumn('deviceTypeIcon');
+ $deviceBrand = $visit->getColumn('deviceBrand');
+ $deviceModel = $visit->getColumn('deviceModel');
+ $deviceName = trim($deviceBrand . " " . $deviceModel);
+
+ if (!isset($this->devices[$deviceType])) {
+ $this->devices[$deviceType] = array(
+ 'count' => 0,
+ 'icon' => $deviceTypeIcon,
+ 'devices' => array()
+ );
+ }
+
+ ++$this->devices[$deviceType]['count'];
+
+ if (!isset($this->devices[$deviceType]['devices'][$deviceName])) {
+ $this->devices[$deviceType]['devices'][$deviceName] = 0;
+ }
+
+ ++$this->devices[$deviceType]['devices'][$deviceName];
+ }
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ $devices = $this->devices;
+ uksort($this->devices, function($a, $b) use ($devices) {
+ $cmp = strcmp($devices[$b]['count'], $devices[$a]['count']);
+ if (0 == $cmp) {
+ $cmp = strcmp($a, $b);
+ }
+ return $cmp;
+ });
+
+ foreach ($this->devices as $type => $devicesData) {
+ $typeDevices = [];
+ foreach ($devicesData['devices'] as $name => $count) {
+ $typeDevices[] = [
+ 'name' => $name,
+ 'count' => $count
+ ];
+ }
+ $this->devices[$type]['devices'] = $typeDevices;
+ }
+
+ $profile['devices'] = $this->devices;
+ }
+} \ No newline at end of file
diff --git a/plugins/DevicesDetection/lang/en.json b/plugins/DevicesDetection/lang/en.json
index 1322f582ab..7015cefe04 100644
--- a/plugins/DevicesDetection/lang/en.json
+++ b/plugins/DevicesDetection/lang/en.json
@@ -38,6 +38,7 @@
"Phablet": "Phablet",
"TV": "Tv",
"UserAgent": "User-Agent",
+ "XVisitsFromDevices": "%1$s visits from %2$s devices",
"WidgetBrowsers": "Visitor Browser",
"WidgetBrowsersDocumentation": "This report contains information about what kind of browser your visitors were using. Each browser version is listed separately."
}
diff --git a/plugins/DevicesDetection/templates/_profileSummary.twig b/plugins/DevicesDetection/templates/_profileSummary.twig
new file mode 100644
index 0000000000..05348864c5
--- /dev/null
+++ b/plugins/DevicesDetection/templates/_profileSummary.twig
@@ -0,0 +1,21 @@
+{% if visitorData.devices is defined %}
+ <div class="visitor-profile-summary visitor-profile-devices">
+ <h1>{{ 'DevicesDetection_Devices'|translate }}</h1>
+ <div>
+ {%- for type,entry in visitorData.devices -%}
+ <p>
+ <img height="16" src="{{ entry.icon }}" />
+ {% if entry.devices|length == 1 and 'General_Unknown'|translate in entry.devices[0].name %}
+ <span>{{ 'DevicesDetection_XVisitsFromDevices'|translate('<strong>' ~ entry.count ~ '</strong>', '<strong>' ~ type ~ '</strong>')|raw }}
+ {% else %}
+ <span>{{ 'DevicesDetection_XVisitsFromDevices'|translate('<strong>' ~ entry.count ~ '</strong>', '<strong>' ~ type ~ '</strong>')|raw }}:
+ {% for device in entry.devices -%}
+ {{ device.name }} ({{ device.count }}x){% if not loop.last %}, {% endif %}
+ {%- endfor -%}
+ </span>
+ {% endif %}
+ </p>
+ {%- endfor -%}
+ </div>
+ </div>
+{% endif %} \ No newline at end of file
diff --git a/plugins/Ecommerce/ProfileSummary/EcommerceSummary.php b/plugins/Ecommerce/ProfileSummary/EcommerceSummary.php
new file mode 100644
index 0000000000..5761549aaf
--- /dev/null
+++ b/plugins/Ecommerce/ProfileSummary/EcommerceSummary.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\Ecommerce\ProfileSummary;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract;
+use Piwik\View;
+
+/**
+ * Class EcommerceSummary
+ *
+ * @api
+ */
+class EcommerceSummary extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('Goals_Ecommerce');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ if (empty($this->profile['totalEcommerceRevenue'])) {
+ return '';
+ }
+
+ $view = new View('@Ecommerce/_profileSummary.twig');
+ $view->idSite = Common::getRequestVar('idSite', null, 'int');
+ $view->visitorData = $this->profile;
+ return $view->render();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 20;
+ }
+} \ No newline at end of file
diff --git a/plugins/Ecommerce/VisitorDetails.php b/plugins/Ecommerce/VisitorDetails.php
new file mode 100644
index 0000000000..f04f38f01d
--- /dev/null
+++ b/plugins/Ecommerce/VisitorDetails.php
@@ -0,0 +1,216 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce;
+
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\DataAccess\LogAggregator;
+use Piwik\Date;
+use Piwik\Db;
+use Piwik\Metrics\Formatter;
+use Piwik\Piwik;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Site;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\GoalManager;
+use Piwik\Tracker\PageUrl;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $ecommerceMetrics = $this->queryEcommerceConversionsVisitorLifeTimeMetricsForVisitor($visitor['idSite'],
+ $visitor['visitorId']);
+ $visitor['totalEcommerceRevenue'] = $ecommerceMetrics['totalEcommerceRevenue'];
+ $visitor['totalEcommerceConversions'] = $ecommerceMetrics['totalEcommerceConversions'];
+ $visitor['totalEcommerceItems'] = $ecommerceMetrics['totalEcommerceItems'];
+
+ $visitor['totalAbandonedCartsRevenue'] = $ecommerceMetrics['totalAbandonedCartsRevenue'];
+ $visitor['totalAbandonedCarts'] = $ecommerceMetrics['totalAbandonedCarts'];
+ $visitor['totalAbandonedCartsItems'] = $ecommerceMetrics['totalAbandonedCartsItems'];
+ }
+
+ public function provideActionsForVisitIds(&$actions, $idVisits)
+ {
+ $ecommerceDetails = $this->queryEcommerceConversionsForVisits($idVisits);
+
+ // use while / array_shift combination instead of foreach to save memory
+ while (is_array($ecommerceDetails) && count($ecommerceDetails)) {
+ $ecommerceDetail = array_shift($ecommerceDetails);
+
+ $idVisit = $ecommerceDetail['idvisit'];
+
+ unset($ecommerceDetail['idvisit']);
+
+ if ($ecommerceDetail['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) {
+ unset($ecommerceDetail['orderId']);
+ unset($ecommerceDetail['revenueSubTotal']);
+ unset($ecommerceDetail['revenueTax']);
+ unset($ecommerceDetail['revenueShipping']);
+ unset($ecommerceDetail['revenueDiscount']);
+ }
+
+ // 25.00 => 25
+ foreach ($ecommerceDetail as $column => $value) {
+ if (strpos($column, 'revenue') !== false) {
+ if ($value == round($value)) {
+ $ecommerceDetail[$column] = round($value);
+ }
+ }
+ }
+
+ $idOrder = isset($ecommerceDetail['orderId']) ? $ecommerceDetail['orderId'] : GoalManager::ITEM_IDORDER_ABANDONED_CART;
+
+ $itemsDetails = $this->queryEcommerceItemsForOrder($idVisit, $idOrder);
+ foreach ($itemsDetails as &$detail) {
+ if ($detail['price'] == round($detail['price'])) {
+ $detail['price'] = round($detail['price']);
+ }
+ }
+ $ecommerceDetail['itemDetails'] = $itemsDetails;
+
+ $actions[$idVisit][] = $ecommerceDetail;
+ }
+ }
+
+ /**
+ * @param $idSite
+ * @param $idVisitor
+ * @return array
+ * @throws \Exception
+ */
+ protected function queryEcommerceConversionsVisitorLifeTimeMetricsForVisitor($idSite, $idVisitor)
+ {
+ $sql = $this->getSqlEcommerceConversionsLifeTimeMetricsForIdGoal(GoalManager::IDGOAL_ORDER);
+ $ecommerceOrders = Db::fetchRow($sql, array($idSite, @Common::hex2bin($idVisitor)));
+
+ $sql = $this->getSqlEcommerceConversionsLifeTimeMetricsForIdGoal(GoalManager::IDGOAL_CART);
+ $abandonedCarts = Db::fetchRow($sql, array($idSite, @Common::hex2bin($idVisitor)));
+
+ return array(
+ 'totalEcommerceRevenue' => $ecommerceOrders['lifeTimeRevenue'],
+ 'totalEcommerceConversions' => $ecommerceOrders['lifeTimeConversions'],
+ 'totalEcommerceItems' => $ecommerceOrders['lifeTimeEcommerceItems'],
+ 'totalAbandonedCartsRevenue' => $abandonedCarts['lifeTimeRevenue'],
+ 'totalAbandonedCarts' => $abandonedCarts['lifeTimeConversions'],
+ 'totalAbandonedCartsItems' => $abandonedCarts['lifeTimeEcommerceItems']
+ );
+ }
+
+
+ /**
+ * @param $ecommerceIdGoal
+ * @return string
+ */
+ protected function getSqlEcommerceConversionsLifeTimeMetricsForIdGoal($ecommerceIdGoal)
+ {
+ $sql = "SELECT
+ COALESCE(SUM(" . LogAggregator::getSqlRevenue('revenue') . "), 0) as lifeTimeRevenue,
+ COUNT(*) as lifeTimeConversions,
+ COALESCE(SUM(" . LogAggregator::getSqlRevenue('items') . "), 0) as lifeTimeEcommerceItems
+ FROM " . Common::prefixTable('log_visit') . " AS log_visit
+ LEFT JOIN " . Common::prefixTable('log_conversion') . " AS log_conversion
+ ON log_visit.idvisit = log_conversion.idvisit
+ WHERE
+ log_visit.idsite = ?
+ AND log_visit.idvisitor = ?
+ AND log_conversion.idgoal = " . $ecommerceIdGoal . "
+ ";
+ return $sql;
+ }
+
+ /**
+ * @param $idVisit
+ * @param $limit
+ * @return array
+ * @throws \Exception
+ */
+ protected function queryEcommerceConversionsForVisits($idVisits)
+ {
+ $sql = "SELECT
+ idvisit,
+ case idgoal when " . GoalManager::IDGOAL_CART
+ . " then '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART
+ . "' else '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER . "' end as type,
+ idorder as orderId,
+ " . LogAggregator::getSqlRevenue('revenue') . " as revenue,
+ " . LogAggregator::getSqlRevenue('revenue_subtotal') . " as revenueSubTotal,
+ " . LogAggregator::getSqlRevenue('revenue_tax') . " as revenueTax,
+ " . LogAggregator::getSqlRevenue('revenue_shipping') . " as revenueShipping,
+ " . LogAggregator::getSqlRevenue('revenue_discount') . " as revenueDiscount,
+ items as items,
+ log_conversion.server_time as serverTimePretty,
+ log_conversion.idlink_va
+ FROM " . Common::prefixTable('log_conversion') . " AS log_conversion
+ WHERE idvisit IN ('" . implode("','", $idVisits) . "')
+ AND idgoal <= " . GoalManager::IDGOAL_ORDER . "
+ ORDER BY idvisit, server_time ASC";
+ $ecommerceDetails = Db::fetchAll($sql);
+ return $ecommerceDetails;
+ }
+
+ /**
+ * @param $idVisit
+ * @param $idOrder
+ * @param $actionsLimit
+ * @return array
+ * @throws \Exception
+ */
+ protected function queryEcommerceItemsForOrder($idVisit, $idOrder)
+ {
+ $sql = "SELECT
+ log_action_sku.name as itemSKU,
+ log_action_name.name as itemName,
+ log_action_category.name as itemCategory,
+ " . LogAggregator::getSqlRevenue('price') . " as price,
+ quantity as quantity
+ FROM " . Common::prefixTable('log_conversion_item') . "
+ INNER JOIN " . Common::prefixTable('log_action') . " AS log_action_sku
+ ON idaction_sku = log_action_sku.idaction
+ LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_name
+ ON idaction_name = log_action_name.idaction
+ LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_category
+ ON idaction_category = log_action_category.idaction
+ WHERE idvisit = ?
+ AND idorder = ?
+ AND deleted = 0
+ ";
+
+ $bind = array($idVisit, $idOrder);
+
+ $itemsDetails = Db::fetchAll($sql, $bind);
+ return $itemsDetails;
+ }
+
+ public function initProfile($visits, &$profile)
+ {
+ if (Site::isEcommerceEnabledFor($visits->getFirstRow()->getColumn('idSite'))) {
+ $profile['totalEcommerceRevenue'] = 0;
+ $profile['totalEcommerceConversions'] = 0;
+ $profile['totalEcommerceItems'] = 0;
+ $profile['totalAbandonedCarts'] = 0;
+ $profile['totalAbandonedCartsRevenue'] = 0;
+ $profile['totalAbandonedCartsItems'] = 0;
+ }
+ }
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ $lastVisit = $visits->getLastRow();
+ if ($lastVisit && Site::isEcommerceEnabledFor($lastVisit->getColumn('idSite'))) {
+ $profile['totalEcommerceRevenue'] = $lastVisit->getColumn('totalEcommerceRevenue');
+ $profile['totalEcommerceConversions'] = $lastVisit->getColumn('totalEcommerceConversions');
+ $profile['totalEcommerceItems'] = $lastVisit->getColumn('totalEcommerceItems');
+ $profile['totalAbandonedCartsRevenue'] = $lastVisit->getColumn('totalAbandonedCartsRevenue');
+ $profile['totalAbandonedCarts'] = $lastVisit->getColumn('totalAbandonedCarts');
+ $profile['totalAbandonedCartsItems'] = $lastVisit->getColumn('totalAbandonedCartsItems');
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Ecommerce/templates/_profileSummary.twig b/plugins/Ecommerce/templates/_profileSummary.twig
new file mode 100644
index 0000000000..b3865096ac
--- /dev/null
+++ b/plugins/Ecommerce/templates/_profileSummary.twig
@@ -0,0 +1,14 @@
+<div class="visitor-profile-summary visitor-profile-lifetimevalue">
+ <h1>{{ 'Goals_Ecommerce'|translate }}</h1>
+ <div>
+ <p title="{{ 'Ecommerce_LifeTimeValueDescription'|translate(visitorData.visitorId) }}">
+ {{ 'Ecommerce_VisitorProfileLTV'|translate( "<strong>" ~ visitorData.totalEcommerceRevenue|money(idSite) ~ "</strong>")|raw }}
+ {{ 'Ecommerce_VisitorProfileItemsAndOrders'|translate("<strong>" ~ visitorData.totalEcommerceItems ~ "</strong>", "<strong>" ~ visitorData.totalEcommerceConversions ~ "</strong>")|raw }}
+ </p>
+ <p>
+ {%- if visitorData.totalAbandonedCarts|default(0) > 0 %}
+ {{ 'Ecommerce_VisitorProfileAbandonedCartSummary'|translate('<strong>' ~ visitorData.totalAbandonedCarts ~ '</strong>', '<strong>' ~ visitorData.totalAbandonedCartsItems ~ '</strong>', '<strong>' ~ visitorData.totalAbandonedCartsRevenue|money(idSite) ~ '</strong>')|raw }}
+ {%- endif -%}
+ </p>
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php
index 8ae0f5cb2e..eee4ce7f52 100644
--- a/plugins/Events/Events.php
+++ b/plugins/Events/Events.php
@@ -27,16 +27,11 @@ class Events extends \Piwik\Plugin
'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations',
'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
'ViewDataTable.configure' => 'configureViewDataTable',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
+ 'Actions.getCustomActionDimensionFieldsAndJoins' => 'provideActionDimensionFields'
);
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $visitor['events'] = $details['visit_total_events'];
- }
-
public function addMetricTranslations(&$translations)
{
$translations = array_merge($translations, $this->getMetricTranslations());
@@ -265,4 +260,14 @@ class Events extends \Piwik\Plugin
{
$stylesheets[] = "plugins/Events/stylesheets/datatable.less";
}
+
+ public function provideActionDimensionFields(&$fields, &$joins)
+ {
+ $fields[] = 'log_action_event_category.name AS eventCategory';
+ $fields[] = 'log_action_event_action.name as eventAction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_event_action
+ ON log_link_visit_action.idaction_event_action = log_action_event_action.idaction';
+ $joins[] = 'LEFT JOIN ' . Common::prefixTable('log_action') . ' AS log_action_event_category
+ ON log_link_visit_action.idaction_event_category = log_action_event_category.idaction';
+ }
}
diff --git a/plugins/Events/VisitorDetails.php b/plugins/Events/VisitorDetails.php
new file mode 100644
index 0000000000..76dfd37806
--- /dev/null
+++ b/plugins/Events/VisitorDetails.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Events;
+
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Tracker\Action;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendActionDetails(&$action, $nextAction, $visitorDetails)
+ {
+ if ($action['type'] == Action::TYPE_EVENT) {
+ $action['type'] = 'event';
+ $action['icon'] = 'plugins/Morpheus/images/event.png';
+ }
+ }
+
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['events'] = $this->details['visit_total_events'];
+ }
+
+ public function renderAction($action, $previousAction, $visitorDetails)
+ {
+ if ($action['type'] != 'event') {
+ return;
+ }
+
+ $view = new View('@Events/_actionEvent.twig');
+ $view->action = $action;
+ $view->previousAction = $previousAction;
+ $view->visitInfo = $visitorDetails;
+ return $view->render();
+ }
+
+
+ public function initProfile($visits, &$profile)
+ {
+ $profile['totalEvents'] = 0;
+ }
+
+ public function handleProfileAction($action, &$profile)
+ {
+ if ($action['type'] != 'event') {
+ return;
+ }
+ $profile['totalEvents']++;
+ }
+} \ No newline at end of file
diff --git a/plugins/Events/templates/_actionEvent.twig b/plugins/Events/templates/_actionEvent.twig
new file mode 100644
index 0000000000..6fa44108b1
--- /dev/null
+++ b/plugins/Events/templates/_actionEvent.twig
@@ -0,0 +1,25 @@
+<li class="action" title="{{ postEvent('Live.renderActionTooltip', action, visitInfo) }}">
+ <div>
+ {% if action.pageTitle|default(false) is not empty %}
+ <span class="truncated-text-line">{{ action.pageTitle|rawSafeDecoded }}</span>
+ {% endif %}
+ <img src='plugins/Morpheus/images/event.png' title='{{ 'Events_Event'|translate }}' class="action-list-action-icon event">
+ <span class="truncated-text-line event">{{ action.eventCategory|rawSafeDecoded }}
+ - {{ action.eventAction|rawSafeDecoded }} {% if action.eventName is defined %}- {{ action.eventName|rawSafeDecoded }}{% endif %} {% if action.eventValue is defined %}[{{ action.eventValue }}]{% endif %}</span>
+ {% if action.url is not empty %}
+ {% if previousAction.url|default(false) == action.url %}
+ {# For events, do not show (url) if the Event URL is the same as the URL last displayed #}
+ {% else %}
+ {% if action.url|trim|lower starts with 'javascript:' or
+ action.url|trim|lower starts with 'vbscript:' or
+ action.url|trim|lower starts with 'data:' %}
+ {{ action.url }}
+ {% else %}
+ <a href="{{ action.url }}" rel="noreferrer" target="_blank" class="truncated-text-line">
+ {{ action.url|replace({'http://': '', 'https://': ''}) }}
+ </a>
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ </div>
+</li>
diff --git a/plugins/Goals/VisitorDetails.php b/plugins/Goals/VisitorDetails.php
new file mode 100644
index 0000000000..0d45b06367
--- /dev/null
+++ b/plugins/Goals/VisitorDetails.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals;
+
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\Date;
+use Piwik\Db;
+use Piwik\Metrics\Formatter;
+use Piwik\Piwik;
+use Piwik\Plugins\CustomVariables\CustomVariables;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Site;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\PageUrl;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ const EVENT_VALUE_PRECISION = 3;
+
+ protected $lastGoalResults = array();
+ protected $lastVisitIds = array();
+
+ public function extendVisitorDetails(&$visitor)
+ {
+ $idVisit = $visitor['idVisit'];
+
+ if (in_array($idVisit, $this->lastVisitIds)) {
+ $goalConversionDetails = isset($this->lastGoalResults[$idVisit]) ? $this->lastGoalResults[$idVisit] : array();
+ } else {
+ $goalConversionDetails = $this->queryGoalConversionsForVisits(array($idVisit));
+ }
+
+ $visitor['goalConversions'] = count($goalConversionDetails);
+ }
+
+ public function provideActionsForVisitIds(&$actions, $idVisits)
+ {
+ $this->lastVisitIds = $idVisits;
+ $this->lastGoalResults = array();
+ $goalConversionDetails = $this->queryGoalConversionsForVisits($idVisits);
+
+ // use while / array_shift combination instead of foreach to save memory
+ while (is_array($goalConversionDetails) && count($goalConversionDetails)) {
+ $goalConversionDetail = array_shift($goalConversionDetails);
+ $idVisit = $goalConversionDetail['idvisit'];
+
+ unset($goalConversionDetail['idvisit']);
+
+ $this->lastGoalResults[$idVisit][] = $actions[$idVisit][] = $goalConversionDetail;
+ }
+ }
+
+ /**
+ * @param $idVisit
+ * @return array
+ * @throws \Exception
+ */
+ protected function queryGoalConversionsForVisits($idVisits)
+ {
+ $sql = "
+ SELECT
+ log_conversion.idvisit,
+ 'goal' as type,
+ goal.name as goalName,
+ goal.idgoal as goalId,
+ log_conversion.revenue as revenue,
+ log_conversion.idlink_va,
+ log_conversion.idlink_va as goalPageId,
+ log_conversion.server_time as serverTimePretty,
+ log_conversion.url as url
+ FROM " . Common::prefixTable('log_conversion') . " AS log_conversion
+ LEFT JOIN " . Common::prefixTable('goal') . " AS goal
+ ON (goal.idsite = log_conversion.idsite
+ AND
+ goal.idgoal = log_conversion.idgoal)
+ AND goal.deleted = 0
+ WHERE log_conversion.idvisit IN ('" . implode("','", $idVisits) . "')
+ AND log_conversion.idgoal > 0
+ ORDER BY log_conversion.idvisit, server_time ASC
+ ";
+ return Db::fetchAll($sql);
+ }
+
+
+ public function initProfile($visits, &$profile)
+ {
+ $profile['totalGoalConversions'] = 0;
+ $profile['totalConversionsByGoal'] = array();
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ $profile['totalGoalConversions'] += $visit->getColumn('goalConversions');
+ }
+
+ public function handleProfileAction($action, &$profile)
+ {
+ if ($action['type'] != 'goal') {
+ return;
+ }
+
+ $idGoal = $action['goalId'];
+ $idGoalKey = 'idgoal=' . $idGoal;
+
+ if (!isset($profile['totalConversionsByGoal'][$idGoalKey])) {
+ $profile['totalConversionsByGoal'][$idGoalKey] = 0;
+ }
+ ++$profile['totalConversionsByGoal'][$idGoalKey];
+
+ if (!empty($action['revenue'])) {
+ if (!isset($profile['totalRevenueByGoal'][$idGoalKey])) {
+ $profile['totalRevenueByGoal'][$idGoalKey] = 0;
+ }
+ $profile['totalRevenueByGoal'][$idGoalKey] += $action['revenue'];
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/API.php b/plugins/Live/API.php
index 8d1649746f..ba655ec1be 100644
--- a/plugins/Live/API.php
+++ b/plugins/Live/API.php
@@ -227,6 +227,8 @@ class API extends \Piwik\Plugin\API
* Triggered in the Live.getVisitorProfile API method. Plugins can use this event
* to discover and add extra data to visitor profiles.
*
+ * This event is deprecated, use [VisitorDetails](/api-reference/Piwik/Plugins/Live/VisitorDetailsAbstract#extendVisitorDetails) classes instead.
+ *
* For example, if an email address is found in a custom variable, a plugin could load the
* gravatar for the email and add it to the visitor profile, causing it to display in the
* visitor profile popup.
@@ -237,6 +239,7 @@ class API extends \Piwik\Plugin\API
* - **visitorDescription**: Text to be used as the tooltip of the avatar image.
*
* @param array &$visitorProfile The unaugmented visitor profile info.
+ * @deprecated
*/
Piwik::postEvent('Live.getExtraVisitorDetails', array(&$result));
@@ -313,40 +316,33 @@ class API extends \Piwik\Plugin\API
$dataTable->$filter(function ($table) use ($idSite, $flat, $doNotFetchActions) {
/** @var DataTable $table */
- $actionsLimit = (int)Config::getInstance()->General['visitor_log_maximum_actions_per_visit'];
-
$visitorFactory = new VisitorFactory();
- $website = new Site($idSite);
- $timezone = $website->getTimezone();
- $currency = $website->getCurrency();
- $currencies = APISitesManager::getInstance()->getCurrencySymbols();
// live api is not summable, prevents errors like "Unexpected ECommerce status value"
$table->deleteRow(DataTable::ID_SUMMARY_ROW);
- foreach ($table->getRows() as $visitorDetailRow) {
- $visitorDetailsArray = Visitor::cleanVisitorDetails($visitorDetailRow->getColumns());
+ $actionsByVisitId = array();
- $visitor = $visitorFactory->create($visitorDetailsArray);
- $visitorDetailsArray = $visitor->getAllVisitorDetails();
+ if (!$doNotFetchActions) {
+ $visitIds = $table->getColumn('idvisit');
- $visitorDetailsArray['siteCurrency'] = $currency;
- $visitorDetailsArray['siteCurrencySymbol'] = @$currencies[$visitorDetailsArray['siteCurrency']];
- $visitorDetailsArray['serverTimestamp'] = $visitorDetailsArray['lastActionTimestamp'];
+ $visitorDetailsManipulators = Visitor::getAllVisitorDetailsInstances();
- $dateTimeVisit = Date::factory($visitorDetailsArray['lastActionTimestamp'], $timezone);
- if ($dateTimeVisit) {
- $visitorDetailsArray['serverTimePretty'] = $dateTimeVisit->getLocalized(Date::TIME_FORMAT);
- $visitorDetailsArray['serverDatePretty'] = $dateTimeVisit->getLocalized(Date::DATE_FORMAT_LONG);
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->provideActionsForVisitIds($actionsByVisitId, $visitIds);
}
+ }
+
+ foreach ($table->getRows() as $visitorDetailRow) {
+ $visitorDetailsArray = Visitor::cleanVisitorDetails($visitorDetailRow->getColumns());
- $dateTimeVisitFirstAction = Date::factory($visitorDetailsArray['firstActionTimestamp'], $timezone);
- $visitorDetailsArray['serverDatePrettyFirstAction'] = $dateTimeVisitFirstAction->getLocalized(Date::DATE_FORMAT_LONG);
- $visitorDetailsArray['serverTimePrettyFirstAction'] = $dateTimeVisitFirstAction->getLocalized(Date::TIME_FORMAT);
+ $visitor = $visitorFactory->create($visitorDetailsArray);
+ $visitorDetailsArray = $visitor->getAllVisitorDetails();
$visitorDetailsArray['actionDetails'] = array();
if (!$doNotFetchActions) {
- $visitorDetailsArray = Visitor::enrichVisitorArrayWithActions($visitorDetailsArray, $actionsLimit, $idSite, $timezone);
+ $bulkFetchedActions = isset($actionsByVisitId[$visitorDetailsArray['idVisit']]) ? $actionsByVisitId[$visitorDetailsArray['idVisit']] : array();
+ $visitorDetailsArray = Visitor::enrichVisitorArrayWithActions($visitorDetailsArray, $bulkFetchedActions);
}
if ($flat) {
diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php
index 3a87d75559..cdcbea995c 100644
--- a/plugins/Live/Controller.php
+++ b/plugins/Live/Controller.php
@@ -9,10 +9,14 @@
namespace Piwik\Plugins\Live;
use Piwik\API\Request;
+use Piwik\Cache;
+use Piwik\CacheId;
use Piwik\Common;
use Piwik\Config;
use Piwik\Piwik;
+use Piwik\Plugin;
use Piwik\Plugins\Goals\API as APIGoals;
+use Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract;
use Piwik\Url;
use Piwik\View;
@@ -111,41 +115,39 @@ class Controller extends \Piwik\Plugin\Controller
$view->visitorData = Request::processRequest('Live.getVisitorProfile');
$view->exportLink = $this->getVisitorProfileExportLink();
- if (Common::getRequestVar('showMap', 1) == 1
- && !empty($view->visitorData['hasLatLong'])
- && \Piwik\Plugin\Manager::getInstance()->isPluginLoaded('UserCountryMap')
- ) {
- $view->userCountryMapUrl = $this->getUserCountryMapUrlForVisitorProfile();
+ $this->setWidgetizedVisitorProfileUrl($view);
+
+ $summaryEntries = array();
+
+ $profileSummaries = self::getAllProfileSummaryInstances();
+ foreach ($profileSummaries as $profileSummary) {
+ $profileSummary->setProfile($view->visitorData);
+ $summaryEntries[] = [$profileSummary->getOrder(), $profileSummary->render()];
}
- $this->setWidgetizedVisitorProfileUrl($view);
+ usort($summaryEntries, function($a, $b) {
+ return version_compare($a[0], $b[0]);
+ });
- return $view->render();
- }
+ $summary = '';
+
+ foreach ($summaryEntries AS $summaryEntry) {
+ $summary .= $summaryEntry[1];
+ }
+
+ $view->profileSummary = $summary;
- public function getSingleVisitSummary()
- {
- $view = new View('@Live/getSingleVisitSummary.twig');
- $visits = Request::processRequest('Live.getLastVisitsDetails', array(
- 'segment' => 'visitId==' . Common::getRequestVar('visitId'),
- 'period' => false,
- 'date' => false
- ));
- $view->visitData = $visits->getFirstRow()->getColumns();
- $view->visitReferralSummary = VisitorProfile::getReferrerSummaryForVisit($visits->getFirstRow());
- $view->showLocation = \Piwik\Plugin\Manager::getInstance()->isPluginLoaded('UserCountry');
- $this->setWidgetizedVisitorProfileUrl($view);
- $view->exportLink = $this->getVisitorProfileExportLink();
return $view->render();
}
public function getVisitList()
{
- $startCounter = Common::getRequestVar('filter_offset', 0, 'int');
+ $filterLimit = Common::getRequestVar('filter_offset', 0, 'int');
+ $startCounter = Common::getRequestVar('start_number', 0, 'int');
$nextVisits = Request::processRequest('Live.getLastVisitsDetails', array(
'segment' => self::getSegmentWithVisitorId(),
'filter_limit' => VisitorProfile::VISITOR_PROFILE_MAX_VISITS_TO_SHOW,
- 'filter_offset' => $startCounter,
+ 'filter_offset' => $filterLimit,
'period' => false,
'date' => false
));
@@ -158,7 +160,7 @@ class Controller extends \Piwik\Plugin\Controller
$view = new View('@Live/getVisitList.twig');
$view->idSite = $idSite;
- $view->startCounter = $startCounter + 1;
+ $view->startCounter = $startCounter < count($nextVisits) ? count($nextVisits) : $startCounter;
$view->visits = $nextVisits;
return $view->render();
}
@@ -186,24 +188,7 @@ class Controller extends \Piwik\Plugin\Controller
}
}
- private function getUserCountryMapUrlForVisitorProfile()
- {
- $params = array(
- 'module' => 'UserCountryMap',
- 'action' => 'realtimeMap',
- 'segment' => self::getSegmentWithVisitorId(),
- 'visitorId' => false,
- 'changeVisitAlpha' => 0,
- 'removeOldVisits' => 0,
- 'realtimeWindow' => 'false',
- 'showFooterMessage' => 0,
- 'showDateTime' => 0,
- 'doNotRefreshVisits' => 1
- );
- return Url::getCurrentQueryStringWithParametersModified($params);
- }
-
- private static function getSegmentWithVisitorId()
+ public static function getSegmentWithVisitorId()
{
static $cached = null;
if ($cached === null) {
@@ -221,4 +206,41 @@ class Controller extends \Piwik\Plugin\Controller
}
return $cached;
}
+
+
+ /**
+ * Returns all available profile summaries
+ *
+ * @return ProfileSummaryAbstract[]
+ * @throws \Exception
+ */
+ public static function getAllProfileSummaryInstances()
+ {
+ $cacheId = CacheId::pluginAware('ProfileSummaries');
+ $cache = Cache::getTransientCache();
+
+ if (!$cache->contains($cacheId)) {
+ $instances = [];
+
+ foreach (self::getAllProfileSummaryClasses() as $className) {
+ $instance = new $className();
+ $instances[] = $instance;
+ }
+
+ $cache->save($cacheId, $instances);
+ }
+
+ return $cache->fetch($cacheId);
+ }
+
+ /**
+ * Returns class names of all VisitorDetails classes.
+ *
+ * @return string[]
+ * @api
+ */
+ protected static function getAllProfileSummaryClasses()
+ {
+ return Plugin\Manager::getInstance()->findMultipleComponents('ProfileSummary', 'Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract');
+ }
}
diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php
index 367d19c3a7..4381adecf2 100644
--- a/plugins/Live/Live.php
+++ b/plugins/Live/Live.php
@@ -2,14 +2,12 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\Live;
-use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-
/**
*
*/
@@ -17,14 +15,18 @@ class Live extends \Piwik\Plugin
{
/**
- * @see Piwik\Plugin::registerEvents
+ * @see \Piwik\Plugin::registerEvents
*/
public function registerEvents()
{
return array(
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
- 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+ 'Live.renderAction' => 'renderAction',
+ 'Live.renderActionTooltip' => 'renderActionTooltip',
+ 'Live.renderVisitorDetails' => 'renderVisitorDetails',
+ 'Live.renderVisitorIcons' => 'renderVisitorIcons',
);
}
@@ -58,4 +60,56 @@ class Live extends \Piwik\Plugin
$translationKeys[] = "General_Segment";
$translationKeys[] = "General_And";
}
+
+ public function renderAction(&$renderedAction, $action, $previousAction, $visitorDetails)
+ {
+ $visitorDetailsInstances = Visitor::getAllVisitorDetailsInstances();
+ foreach ($visitorDetailsInstances as $instance) {
+ $renderedAction .= $instance->renderAction($action, $previousAction, $visitorDetails);
+ }
+ }
+
+ public function renderActionTooltip(&$tooltip, $action, $visitInfo)
+ {
+ $detailEntries = [];
+ $visitorDetailsInstances = Visitor::getAllVisitorDetailsInstances();
+
+ foreach ($visitorDetailsInstances as $instance) {
+ $detailEntries = array_merge($detailEntries, $instance->renderActionTooltip($action, $visitInfo));
+ }
+
+ usort($detailEntries, function($a, $b) {
+ return version_compare($a[0], $b[0]);
+ });
+
+ foreach ($detailEntries AS $detailEntry) {
+ $tooltip .= $detailEntry[1];
+ }
+ }
+
+ public function renderVisitorDetails(&$renderedDetails, $visitorDetails)
+ {
+ $detailEntries = [];
+ $visitorDetailsInstances = Visitor::getAllVisitorDetailsInstances();
+
+ foreach ($visitorDetailsInstances as $instance) {
+ $detailEntries = array_merge($detailEntries, $instance->renderVisitorDetails($visitorDetails));
+ }
+
+ usort($detailEntries, function($a, $b) {
+ return version_compare($a[0], $b[0]);
+ });
+
+ foreach ($detailEntries AS $detailEntry) {
+ $renderedDetails .= $detailEntry[1];
+ }
+ }
+
+ public function renderVisitorIcons(&$renderedDetails, $visitorDetails)
+ {
+ $visitorDetailsInstances = Visitor::getAllVisitorDetailsInstances();
+ foreach ($visitorDetailsInstances as $instance) {
+ $renderedDetails .= $instance->renderIcons($visitorDetails);
+ }
+ }
} \ No newline at end of file
diff --git a/plugins/Live/Model.php b/plugins/Live/Model.php
index e19054b4d7..a475536da5 100644
--- a/plugins/Live/Model.php
+++ b/plugins/Live/Model.php
@@ -24,177 +24,6 @@ use Piwik\Tracker\GoalManager;
class Model
{
-
- /**
- * @param $idVisit
- * @param $actionsLimit
- * @return array
- * @throws \Exception
- */
- public function queryActionsForVisit($idVisit, $actionsLimit)
- {
- $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
-
- $sqlCustomVariables = '';
- for ($i = 1; $i <= $maxCustomVariables; $i++) {
- $sqlCustomVariables .= ', custom_var_k' . $i . ', custom_var_v' . $i;
- }
- // The second join is a LEFT join to allow returning records that don't have a matching page title
- // eg. Downloads, Outlinks. For these, idaction_name is set to 0
- $sql = "
- SELECT
- COALESCE(log_action_event_category.type, log_action.type, log_action_title.type) AS type,
- log_action.name AS url,
- log_action.url_prefix,
- log_action_title.name AS pageTitle,
- log_action.idaction AS pageIdAction,
- log_link_visit_action.idlink_va,
- log_link_visit_action.server_time as serverTimePretty,
- log_link_visit_action.time_spent_ref_action as timeSpentRef,
- log_link_visit_action.idlink_va AS pageId,
- log_link_visit_action.custom_float,
- log_link_visit_action.interaction_position
- " . $sqlCustomVariables . ",
- log_action_event_category.name AS eventCategory,
- log_action_event_action.name as eventAction
- FROM " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action
- ON log_link_visit_action.idaction_url = log_action.idaction
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_title
- ON log_link_visit_action.idaction_name = log_action_title.idaction
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_category
- ON log_link_visit_action.idaction_event_category = log_action_event_category.idaction
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_action
- ON log_link_visit_action.idaction_event_action = log_action_event_action.idaction
- WHERE log_link_visit_action.idvisit = ?
- ORDER BY server_time ASC
- LIMIT 0, $actionsLimit
- ";
- $actionDetails = Db::fetchAll($sql, array($idVisit));
- return $actionDetails;
- }
-
- /**
- * @param $idVisit
- * @param $limit
- * @return array
- * @throws \Exception
- */
- public function queryGoalConversionsForVisit($idVisit, $limit)
- {
- $sql = "
- SELECT
- 'goal' as type,
- goal.name as goalName,
- goal.idgoal as goalId,
- log_conversion.revenue as revenue,
- log_conversion.idlink_va,
- log_conversion.idlink_va as goalPageId,
- log_conversion.server_time as serverTimePretty,
- log_conversion.url as url
- FROM " . Common::prefixTable('log_conversion') . " AS log_conversion
- LEFT JOIN " . Common::prefixTable('goal') . " AS goal
- ON (goal.idsite = log_conversion.idsite
- AND
- goal.idgoal = log_conversion.idgoal)
- AND goal.deleted = 0
- WHERE log_conversion.idvisit = ?
- AND log_conversion.idgoal > 0
- ORDER BY server_time ASC
- LIMIT 0, $limit
- ";
- $goalDetails = Db::fetchAll($sql, array($idVisit));
- return $goalDetails;
- }
-
- /**
- * @param $idVisit
- * @param $limit
- * @return array
- * @throws \Exception
- */
- public function queryEcommerceConversionsForVisit($idVisit, $limit)
- {
- $sql = "SELECT
- case idgoal when " . GoalManager::IDGOAL_CART
- . " then '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART
- . "' else '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER . "' end as type,
- idorder as orderId,
- " . LogAggregator::getSqlRevenue('revenue') . " as revenue,
- " . LogAggregator::getSqlRevenue('revenue_subtotal') . " as revenueSubTotal,
- " . LogAggregator::getSqlRevenue('revenue_tax') . " as revenueTax,
- " . LogAggregator::getSqlRevenue('revenue_shipping') . " as revenueShipping,
- " . LogAggregator::getSqlRevenue('revenue_discount') . " as revenueDiscount,
- items as items,
- log_conversion.server_time as serverTimePretty,
- log_conversion.idlink_va
- FROM " . Common::prefixTable('log_conversion') . " AS log_conversion
- WHERE idvisit = ?
- AND idgoal <= " . GoalManager::IDGOAL_ORDER . "
- ORDER BY server_time ASC
- LIMIT 0, $limit";
- $ecommerceDetails = Db::fetchAll($sql, array($idVisit));
- return $ecommerceDetails;
- }
-
- /**
- * @param $idSite
- * @param $idVisit
- * @return array
- * @throws \Exception
- */
- public function queryEcommerceConversionsVisitorLifeTimeMetricsForVisitor($idSite, $idVisitor)
- {
- $sql = $this->getSqlEcommerceConversionsLifeTimeMetricsForIdGoal(GoalManager::IDGOAL_ORDER);
- $ecommerceOrders = Db::fetchRow($sql, array($idSite, @Common::hex2bin($idVisitor)));
-
- $sql = $this->getSqlEcommerceConversionsLifeTimeMetricsForIdGoal(GoalManager::IDGOAL_CART);
- $abandonedCarts = Db::fetchRow($sql, array($idSite, @Common::hex2bin($idVisitor)));
-
- return array(
- 'totalEcommerceRevenue' => $ecommerceOrders['lifeTimeRevenue'],
- 'totalEcommerceConversions' => $ecommerceOrders['lifeTimeConversions'],
- 'totalEcommerceItems' => $ecommerceOrders['lifeTimeEcommerceItems'],
- 'totalAbandonedCartsRevenue' => $abandonedCarts['lifeTimeRevenue'],
- 'totalAbandonedCarts' => $abandonedCarts['lifeTimeConversions'],
- 'totalAbandonedCartsItems' => $abandonedCarts['lifeTimeEcommerceItems']
- );
- }
-
- /**
- * @param $idVisit
- * @param $idOrder
- * @param $actionsLimit
- * @return array
- * @throws \Exception
- */
- public function queryEcommerceItemsForOrder($idVisit, $idOrder, $actionsLimit)
- {
- $sql = "SELECT
- log_action_sku.name as itemSKU,
- log_action_name.name as itemName,
- log_action_category.name as itemCategory,
- " . LogAggregator::getSqlRevenue('price') . " as price,
- quantity as quantity
- FROM " . Common::prefixTable('log_conversion_item') . "
- INNER JOIN " . Common::prefixTable('log_action') . " AS log_action_sku
- ON idaction_sku = log_action_sku.idaction
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_name
- ON idaction_name = log_action_name.idaction
- LEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_category
- ON idaction_category = log_action_category.idaction
- WHERE idvisit = ?
- AND idorder = ?
- AND deleted = 0
- LIMIT 0, $actionsLimit
- ";
-
- $bind = array($idVisit, $idOrder);
-
- $itemsDetails = Db::fetchAll($sql, $bind);
- return $itemsDetails;
- }
-
/**
* @param $idSite
* @param $period
@@ -538,25 +367,4 @@ class Model
}
return array($whereBind, $where);
}
-
- /**
- * @param $ecommerceIdGoal
- * @return string
- */
- private function getSqlEcommerceConversionsLifeTimeMetricsForIdGoal($ecommerceIdGoal)
- {
- $sql = "SELECT
- COALESCE(SUM(" . LogAggregator::getSqlRevenue('revenue') . "), 0) as lifeTimeRevenue,
- COUNT(*) as lifeTimeConversions,
- COALESCE(SUM(" . LogAggregator::getSqlRevenue('items') . "), 0) as lifeTimeEcommerceItems
- FROM " . Common::prefixTable('log_visit') . " AS log_visit
- LEFT JOIN " . Common::prefixTable('log_conversion') . " AS log_conversion
- ON log_visit.idvisit = log_conversion.idvisit
- WHERE
- log_visit.idsite = ?
- AND log_visit.idvisitor = ?
- AND log_conversion.idgoal = " . $ecommerceIdGoal . "
- ";
- return $sql;
- }
-}
+}
diff --git a/plugins/Live/ProfileSummary/ImportantVisits.php b/plugins/Live/ProfileSummary/ImportantVisits.php
new file mode 100644
index 0000000000..afb290b505
--- /dev/null
+++ b/plugins/Live/ProfileSummary/ImportantVisits.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\Live\ProfileSummary;
+
+use Piwik\Piwik;
+use Piwik\View;
+
+/**
+ * Class ImportantVisits
+ *
+ * @api
+ */
+class ImportantVisits extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('General_Summary');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ $viewVisits = new View('@Live/_profileSummaryVisits.twig');
+ $viewVisits->visitorData = $this->profile;
+ return $viewVisits->render();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 30;
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/ProfileSummary/ProfileSummaryAbstract.php b/plugins/Live/ProfileSummary/ProfileSummaryAbstract.php
new file mode 100644
index 0000000000..e1e0f7d0bb
--- /dev/null
+++ b/plugins/Live/ProfileSummary/ProfileSummaryAbstract.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\ProfileSummary;
+
+/**
+ * Class ProfileSummaryAbstract
+ *
+ * This class can be implemented in a plugin to provide a new profile summary
+ *
+ * @api
+ */
+abstract class ProfileSummaryAbstract
+{
+ /**
+ * Visitor profile information
+ *
+ * @var array
+ */
+ protected $profile = [];
+
+ /**
+ * Set profile information
+ *
+ * @param array $profile
+ */
+ public function setProfile($profile)
+ {
+ $this->profile = $profile;
+ }
+
+ /**
+ * Returns the unique ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return static::class;
+ }
+
+ /**
+ * Returns the descriptive name
+ *
+ * @return string
+ */
+ abstract function getName();
+
+ /**
+ * Renders and returns the summary
+ *
+ * @return string
+ */
+ abstract function render();
+
+ /**
+ * Returns order indicator used to sort all summaries before displaying them
+ *
+ * @return int
+ */
+ abstract function getOrder();
+} \ No newline at end of file
diff --git a/plugins/Live/ProfileSummary/Summary.php b/plugins/Live/ProfileSummary/Summary.php
new file mode 100644
index 0000000000..db81a8e127
--- /dev/null
+++ b/plugins/Live/ProfileSummary/Summary.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\ProfileSummary;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\View;
+use Piwik\Plugins\Goals\API as APIGoals;
+
+/**
+ * Class ProfileSummaryAbstract
+ *
+ * This class can be implemented in a plugin to provide a new profile summary
+ *
+ * @api
+ */
+class Summary extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('General_Summary');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ $idSite = Common::getRequestVar('idSite', null, 'int');
+ $view = new View('@Live/_profileSummary.twig');
+ $view->goals = APIGoals::getInstance()->getGoals($idSite);
+ $view->visitorData = $this->profile;
+ return $view->render();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 0;
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php
index 19844f0f71..4984c262ca 100644
--- a/plugins/Live/Visitor.php
+++ b/plugins/Live/Visitor.php
@@ -8,24 +8,18 @@
*/
namespace Piwik\Plugins\Live;
-use Piwik\Common;
+use Piwik\Cache;
+use Piwik\CacheId;
+use Piwik\Config;
use Piwik\DataTable\Filter\ColumnDelete;
use Piwik\Date;
-use Piwik\Db;
use Piwik\Metrics\Formatter;
-use Piwik\Network\IPUtils;
+use Piwik\Plugin;
use Piwik\Piwik;
-use Piwik\Plugins\CustomVariables\CustomVariables;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
-use Piwik\Plugins\Actions\Actions\ActionSiteSearch;
-use Piwik\Tracker;
-use Piwik\Tracker\Action;
use Piwik\Tracker\GoalManager;
class Visitor implements VisitorInterface
{
- const EVENT_VALUE_PRECISION = 3;
-
private $details = array();
function __construct($visitorRawData)
@@ -35,24 +29,14 @@ class Visitor implements VisitorInterface
function getAllVisitorDetails()
{
- $visitor = array(
- 'idSite' => $this->getIdSite(),
- 'idVisit' => $this->getIdVisit(),
- 'visitIp' => $this->getIp(),
- 'visitorId' => $this->getVisitorId(),
-
- // => false are placeholders to be filled in API later
- 'actionDetails' => false,
- 'goalConversions' => false,
- 'siteCurrency' => false,
- 'siteCurrencySymbol' => false,
-
- // all time entries
- 'serverDate' => $this->getServerDate(),
- 'visitServerHour' => $this->getVisitServerHour(),
- 'lastActionTimestamp' => $this->getTimestampLastAction(),
- 'lastActionDateTime' => $this->getDateTimeLastAction(),
- );
+ $visitor = array();
+
+ $instances = self::getAllVisitorDetailsInstances();
+
+ foreach ($instances as $instance) {
+ $instance->setDetails($this->details);
+ $instance->extendVisitorDetails($visitor);
+ }
/**
* This event can be used to add any details to a visitor. The visitor's details are for instance used in
@@ -70,56 +54,63 @@ class Visitor implements VisitorInterface
*
* @param array &visitor You can add or remove fields to the visitor array and it will reflected in the API output
* @param array $details The details array contains all visit dimensions (columns of log_visit table)
+ *
+ * @deprecated will be removed in Piwik 4
*/
Piwik::postEvent('Live.getAllVisitorDetails', array(&$visitor, $this->details));
return $visitor;
}
- function getVisitorId()
+ /**
+ * Returns all available visitor details instances
+ *
+ * @return VisitorDetailsAbstract[]
+ * @throws \Exception
+ */
+ public static function getAllVisitorDetailsInstances()
{
- if (isset($this->details['idvisitor'])) {
- return bin2hex($this->details['idvisitor']);
- }
- return false;
- }
+ $cacheId = CacheId::pluginAware('VisitorDetails');
+ $cache = Cache::getTransientCache();
- function getVisitServerHour()
- {
- return date('G', strtotime($this->details['visit_last_action_time']));
- }
+ if (!$cache->contains($cacheId)) {
+ $instances = [
+ new VisitorDetails() // needs to be first
+ ];
- function getServerDate()
- {
- return date('Y-m-d', strtotime($this->details['visit_last_action_time']));
- }
+ foreach (self::getAllVisitorDetailsClasses() as $className) {
+ $instance = new $className();
- function getIp()
- {
- if (isset($this->details['location_ip'])) {
- return IPUtils::binaryToStringIP($this->details['location_ip']);
- }
- return null;
- }
+ if ($instance instanceof VisitorDetails) {
+ continue;
+ }
- function getIdVisit()
- {
- return $this->details['idvisit'];
- }
+ $instances[] = $instance;
+ }
- function getIdSite()
- {
- return $this->details['idsite'];
+ $cache->save($cacheId, $instances);
+ }
+
+ return $cache->fetch($cacheId);
}
- function getTimestampLastAction()
+ /**
+ * Returns class names of all VisitorDetails classes.
+ *
+ * @return string[]
+ * @api
+ */
+ protected static function getAllVisitorDetailsClasses()
{
- return strtotime($this->details['visit_last_action_time']);
+ return Plugin\Manager::getInstance()->findComponents('VisitorDetails', 'Piwik\Plugins\Live\VisitorDetailsAbstract');
}
- function getDateTimeLastAction()
+ function getVisitorId()
{
- return date('Y-m-d H:i:s', strtotime($this->details['visit_last_action_time']));
+ if (isset($this->details['idvisitor'])) {
+ return bin2hex($this->details['idvisitor']);
+ }
+ return false;
}
/**
@@ -246,232 +237,48 @@ class Visitor implements VisitorInterface
}
/**
- * @param $visitorDetailsArray
- * @param $actionsLimit
- * @param $timezone
+ * @param array $visitorDetailsArray
+ * @param array $actionDetails preset action details
+ *
* @return array
*/
- public static function enrichVisitorArrayWithActions($visitorDetailsArray, $actionsLimit, $idSite, $timezone)
+ public static function enrichVisitorArrayWithActions($visitorDetailsArray, $actionDetails = array())
{
- $idVisit = $visitorDetailsArray['idVisit'];
-
- $model = new Model();
- $actionDetails = $model->queryActionsForVisit($idVisit, $actionsLimit);
-
- $formatter = new Formatter();
- $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
+ $actionsLimit = (int)Config::getInstance()->General['visitor_log_maximum_actions_per_visit'];
+ $visitorDetailsManipulators = self::getAllVisitorDetailsInstances();
- foreach ($actionDetails as $actionIdx => &$actionDetail) {
- $actionDetail =& $actionDetails[$actionIdx];
- $customVariablesPage = array();
-
- for ($i = 1; $i <= $maxCustomVariables; $i++) {
- if (!empty($actionDetail['custom_var_k' . $i])) {
- $cvarKey = $actionDetail['custom_var_k' . $i];
- $cvarKey = static::getCustomVariablePrettyKey($cvarKey);
- $customVariablesPage[$i] = array(
- 'customVariablePageName' . $i => $cvarKey,
- 'customVariablePageValue' . $i => $actionDetail['custom_var_v' . $i],
- );
- }
- unset($actionDetail['custom_var_k' . $i]);
- unset($actionDetail['custom_var_v' . $i]);
- }
- if (!empty($customVariablesPage)) {
- $actionDetail['customVariables'] = $customVariablesPage;
- }
-
- if ($actionDetail['type'] == Action::TYPE_CONTENT) {
-
- unset($actionDetails[$actionIdx]);
- continue;
-
- } elseif ($actionDetail['type'] == Action::TYPE_EVENT) {
- // Handle Event
- if (strlen($actionDetail['pageTitle']) > 0) {
- $actionDetail['eventName'] = $actionDetail['pageTitle'];
- }
-
- unset($actionDetail['pageTitle']);
-
- } else if ($actionDetail['type'] == Action::TYPE_SITE_SEARCH) {
- // Handle Site Search
- $actionDetail['siteSearchKeyword'] = $actionDetail['pageTitle'];
- unset($actionDetail['pageTitle']);
- }
-
- // Event value / Generation time
- if ($actionDetail['type'] == Action::TYPE_EVENT) {
- if (strlen($actionDetail['custom_float']) > 0) {
- $actionDetail['eventValue'] = round($actionDetail['custom_float'], self::EVENT_VALUE_PRECISION);
- }
- } elseif ($actionDetail['custom_float'] > 0) {
- $actionDetail['generationTimeMilliseconds'] = $actionDetail['custom_float'];
- $actionDetail['generationTime'] = $formatter->getPrettyTimeFromSeconds($actionDetail['custom_float'] / 1000, true);
- }
- unset($actionDetail['custom_float']);
-
- if ($actionDetail['type'] != Action::TYPE_EVENT) {
- unset($actionDetail['eventCategory']);
- unset($actionDetail['eventAction']);
- }
-
- $actionDetail['interactionPosition'] = $actionDetail['interaction_position'];
- unset($actionDetail['interaction_position']);
-
- // Reconstruct url from prefix
- $url = Tracker\PageUrl::reconstructNormalizedUrl($actionDetail['url'], $actionDetail['url_prefix']);
- $url = Common::unsanitizeInputValue($url);
-
- $actionDetail['url'] = $url;
- unset($actionDetail['url_prefix']);
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->provideActionsForVisit($actionDetails, $visitorDetailsArray);
}
- // If the visitor converted a goal, we shall select all Goals
- $goalDetails = $model->queryGoalConversionsForVisit($idVisit, $actionsLimit);
-
- $ecommerceMetrics = $model->queryEcommerceConversionsVisitorLifeTimeMetricsForVisitor($idSite, $visitorDetailsArray['visitorId']);
- $visitorDetailsArray['totalEcommerceRevenue'] = $ecommerceMetrics['totalEcommerceRevenue'];
- $visitorDetailsArray['totalEcommerceConversions'] = $ecommerceMetrics['totalEcommerceConversions'];
- $visitorDetailsArray['totalEcommerceItems'] = $ecommerceMetrics['totalEcommerceItems'];
-
- $visitorDetailsArray['totalAbandonedCartsRevenue'] = $ecommerceMetrics['totalAbandonedCartsRevenue'];
- $visitorDetailsArray['totalAbandonedCarts'] = $ecommerceMetrics['totalAbandonedCarts'];
- $visitorDetailsArray['totalAbandonedCartsItems'] = $ecommerceMetrics['totalAbandonedCartsItems'];
-
- $ecommerceDetails = $model->queryEcommerceConversionsForVisit($idVisit, $actionsLimit);
- foreach ($ecommerceDetails as &$ecommerceDetail) {
- if ($ecommerceDetail['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) {
- unset($ecommerceDetail['orderId']);
- unset($ecommerceDetail['revenueSubTotal']);
- unset($ecommerceDetail['revenueTax']);
- unset($ecommerceDetail['revenueShipping']);
- unset($ecommerceDetail['revenueDiscount']);
- }
-
- // 25.00 => 25
- foreach ($ecommerceDetail as $column => $value) {
- if (strpos($column, 'revenue') !== false) {
- if ($value == round($value)) {
- $ecommerceDetail[$column] = round($value);
- }
- }
- }
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->filterActions($actionDetails, $visitorDetailsArray);
}
- // Enrich ecommerce carts/orders with the list of products
- usort($ecommerceDetails, array('static', 'sortByServerTime'));
- foreach ($ecommerceDetails as &$ecommerceConversion) {
- $idOrder = isset($ecommerceConversion['orderId']) ? $ecommerceConversion['orderId'] : GoalManager::ITEM_IDORDER_ABANDONED_CART;
-
- $itemsDetails = $model->queryEcommerceItemsForOrder($idVisit, $idOrder, $actionsLimit);
- foreach ($itemsDetails as &$detail) {
- if ($detail['price'] == round($detail['price'])) {
- $detail['price'] = round($detail['price']);
- }
- }
- $ecommerceConversion['itemDetails'] = $itemsDetails;
- }
+ usort($actionDetails, array('static', 'sortByServerTime'));
$actionDetails = array_values($actionDetails);
- // Enrich with time spent per action
- foreach($actionDetails as $actionIdx => &$actionDetail) {
-
- // Set the time spent for this action (which is the timeSpentRef of the next action)
- $nextActionFound = isset($actionDetails[$actionIdx + 1]);
- if ($nextActionFound) {
- $actionDetail['timeSpent'] = $actionDetails[$actionIdx + 1]['timeSpentRef'];
- } else {
-
- // Last action of a visit.
- // By default, Piwik does not know how long the user stayed on the page
- // If enableHeartBeatTimer() is used in piwik.js then we can find the accurate time on page for the last pageview
- $visitTotalTime = $visitorDetailsArray['visitDuration'];
- $timeOfLastAction = Date::factory($actionDetail['serverTimePretty'])->getTimestamp();
-
- $timeSpentOnAllActionsApartFromLastOne = ($timeOfLastAction - $visitorDetailsArray['firstActionTimestamp']);
- $timeSpentOnPage = $visitTotalTime - $timeSpentOnAllActionsApartFromLastOne;
-
- // Safe net, we assume the time is correct when it's more than 10 seconds
- if ($timeSpentOnPage > 10) {
- $actionDetail['timeSpent'] = $timeSpentOnPage;
- }
-
- }
-
- if (isset($actionDetail['timeSpent'])) {
- $actionDetail['timeSpentPretty'] = $formatter->getPrettyTimeFromSeconds($actionDetail['timeSpent'], true);
- }
-
- unset($actionDetails[$actionIdx]['timeSpentRef']); // not needed after timeSpent is added
-
+ // limit actions
+ if ($actionsLimit < count($actionDetails)) {
+ $visitorDetailsArray['truncatedActionsCount'] = count($actionDetails) - $actionsLimit;
+ $actionDetails = array_slice($actionDetails, 0, $actionsLimit);
}
- $actions = array_merge($actionDetails, $goalDetails, $ecommerceDetails);
- usort($actions, array('static', 'sortByServerTime'));
-
- foreach ($actions as &$action) {
- unset($action['idlink_va']);
- }
+ foreach ($actionDetails as $actionIdx => &$actionDetail) {
+ $actionDetail =& $actionDetails[$actionIdx];
+ $nextAction = isset($actionDetails[$actionIdx+1]) ? $actionDetails[$actionIdx+1] : null;
- $visitorDetailsArray['goalConversions'] = count($goalDetails);
-
- $visitorDetailsArray['actionDetails'] = $actions;
-
- foreach ($visitorDetailsArray['actionDetails'] as &$details) {
- switch ($details['type']) {
- case 'goal':
- $details['icon'] = 'plugins/Morpheus/images/goal.png';
- break;
- case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER:
- case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART:
- $details['icon'] = 'plugins/Morpheus/images/' . $details['type'] . '.png';
- break;
- case Action::TYPE_DOWNLOAD:
- $details['type'] = 'download';
- $details['icon'] = 'plugins/Morpheus/images/download.png';
- break;
- case Action::TYPE_OUTLINK:
- $details['type'] = 'outlink';
- $details['icon'] = 'plugins/Morpheus/images/link.png';
- break;
- case Action::TYPE_SITE_SEARCH:
- $details['type'] = 'search';
- $details['icon'] = 'plugins/Morpheus/images/search_ico.png';
- break;
- case Action::TYPE_EVENT:
- $details['type'] = 'event';
- $details['icon'] = 'plugins/Morpheus/images/event.png';
- break;
- default:
- $details['type'] = 'action';
- $details['icon'] = null;
- break;
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->extendActionDetails($actionDetail, $nextAction, $visitorDetailsArray);
}
-
- // Convert datetimes to the site timezone
- $dateTimeVisit = Date::factory($details['serverTimePretty'], $timezone);
- $details['serverTimePretty'] = $dateTimeVisit->getLocalized(Date::DATETIME_FORMAT_SHORT);
- $details['timestamp'] = $dateTimeVisit->getTimestamp();
}
+ $visitorDetailsArray['actionDetails'] = $actionDetails;
return $visitorDetailsArray;
}
- private static function getCustomVariablePrettyKey($key)
- {
- $rename = array(
- ActionSiteSearch::CVAR_KEY_SEARCH_CATEGORY => Piwik::translate('Actions_ColumnSearchCategory'),
- ActionSiteSearch::CVAR_KEY_SEARCH_COUNT => Piwik::translate('Actions_ColumnSearchResultsCount'),
- );
- if (isset($rename[$key])) {
- return $rename[$key];
- }
- return $key;
- }
-
private static function sortByServerTime($a, $b)
{
$ta = strtotime($a['serverTimePretty']);
diff --git a/plugins/Live/VisitorDetails.php b/plugins/Live/VisitorDetails.php
new file mode 100644
index 0000000000..91be2f543b
--- /dev/null
+++ b/plugins/Live/VisitorDetails.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live;
+
+use Piwik\Date;
+use Piwik\DataTable;
+use Piwik\Metrics\Formatter;
+use Piwik\Network\IPUtils;
+use Piwik\Piwik;
+use Piwik\Site;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\Plugins\Referrers\API as APIReferrers;
+use Piwik\View;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $idSite = $this->getIdSite();
+ $website = new Site($idSite);
+ $timezone = $website->getTimezone();
+ $currency = $website->getCurrency();
+ $currencies = APISitesManager::getInstance()->getCurrencySymbols();
+
+ $visitor += array(
+ 'idSite' => $idSite,
+ 'idVisit' => $this->getIdVisit(),
+ 'visitIp' => $this->getIp(),
+ 'visitorId' => $this->getVisitorId(),
+
+ // => false are placeholders to be filled in API later
+ 'actionDetails' => false,
+ 'goalConversions' => false,
+ 'siteCurrency' => false,
+ 'siteCurrencySymbol' => false,
+
+ // all time entries
+ 'serverDate' => $this->getServerDate(),
+ 'visitServerHour' => $this->getVisitServerHour(),
+ 'lastActionTimestamp' => $this->getTimestampLastAction(),
+ 'lastActionDateTime' => $this->getDateTimeLastAction(),
+ );
+
+ $visitor['siteCurrency'] = $currency;
+ $visitor['siteCurrencySymbol'] = @$currencies[$visitor['siteCurrency']];
+ $visitor['serverTimestamp'] = $visitor['lastActionTimestamp'];
+ $visitor['firstActionTimestamp'] = strtotime($this->details['visit_first_action_time']);
+
+ $dateTimeVisit = Date::factory($visitor['lastActionTimestamp'], $timezone);
+ if ($dateTimeVisit) {
+ $visitor['serverTimePretty'] = $dateTimeVisit->getLocalized(Date::TIME_FORMAT);
+ $visitor['serverDatePretty'] = $dateTimeVisit->getLocalized(Date::DATE_FORMAT_LONG);
+ }
+
+ $dateTimeVisitFirstAction = Date::factory($visitor['firstActionTimestamp'], $timezone);
+ $visitor['serverDatePrettyFirstAction'] = $dateTimeVisitFirstAction->getLocalized(Date::DATE_FORMAT_LONG);
+ $visitor['serverTimePrettyFirstAction'] = $dateTimeVisitFirstAction->getLocalized(Date::TIME_FORMAT);
+ }
+
+ public function renderAction($action, $previousAction, $visitorDetails)
+ {
+ switch ($action['type']) {
+ case 'ecommerceOrder':
+ case 'ecommerceAbandonedCart':
+ $template = '@Live/_actionEcommerce.twig';
+ break;
+ case 'goal':
+ $template = '@Live/_actionGoal.twig';
+ break;
+ case 'action':
+ case 'search':
+ case 'outlink':
+ case 'download':
+ $template = '@Live/_actionCommon.twig';
+ break;
+ }
+
+ if (empty($template)) {
+ return;
+ }
+
+ $view = new View($template);
+ $view->action = $action;
+ $view->previousAction = $previousAction;
+ $view->visitInfo = $visitorDetails;
+ return $view->render();
+ }
+
+ public function renderActionTooltip($action, $visitInfo)
+ {
+ $view = new View('@Live/_actionTooltip');
+ $view->action = $action;
+ $view->visitInfo = $visitInfo;
+ return [[ 0, $view->render() ]];
+ }
+
+ public function renderVisitorDetails($visitorDetails)
+ {
+ $view = new View('@Live/_visitorDetails.twig');
+ $view->visitInfo = $visitorDetails;
+ return [[ 0, $view->render() ]];
+ }
+
+ public function renderIcons($visitorDetails)
+ {
+ $view = new View('@Live/_visitorLogIcons.twig');
+ $view->visitor = $visitorDetails;
+ return $view->render();
+ }
+
+ function getVisitorId()
+ {
+ if (isset($this->details['idvisitor'])) {
+ return bin2hex($this->details['idvisitor']);
+ }
+ return false;
+ }
+
+ function getVisitServerHour()
+ {
+ return date('G', strtotime($this->details['visit_last_action_time']));
+ }
+
+ function getServerDate()
+ {
+ return date('Y-m-d', strtotime($this->details['visit_last_action_time']));
+ }
+
+ function getIp()
+ {
+ if (isset($this->details['location_ip'])) {
+ return IPUtils::binaryToStringIP($this->details['location_ip']);
+ }
+ return null;
+ }
+
+ function getIdVisit()
+ {
+ return $this->details['idvisit'];
+ }
+
+ function getIdSite()
+ {
+ return $this->details['idsite'];
+ }
+
+ function getTimestampLastAction()
+ {
+ return strtotime($this->details['visit_last_action_time']);
+ }
+
+ function getDateTimeLastAction()
+ {
+ return date('Y-m-d H:i:s', strtotime($this->details['visit_last_action_time']));
+ }
+
+
+ public function initProfile($visits, &$profile)
+ {
+ $profile['totalVisits'] = 0;
+ $profile['totalVisitDuration'] = 0;
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ ++$profile['totalVisits'];
+
+ $profile['totalVisitDuration'] += $visit->getColumn('visitDuration');
+ }
+
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ $formatter = new Formatter();
+ $profile['totalVisitDurationPretty'] = $formatter->getPrettyTimeFromSeconds($profile['totalVisitDuration'], true);
+
+ $rows = $visits->getRows();
+ $profile['userId'] = $visits->getLastRow()->getColumn('userId');
+ $profile['firstVisit'] = $this->getVisitorProfileVisitSummary(end($rows));
+ $profile['lastVisit'] = $this->getVisitorProfileVisitSummary(reset($rows));
+ $profile['visitsAggregated'] = count($rows);
+ }
+
+ /**
+ * Returns a summary for an important visit. Used to describe the first & last visits of a visitor.
+ *
+ * @param DataTable\Row $visit
+ * @return array
+ */
+ private function getVisitorProfileVisitSummary($visit)
+ {
+ $today = Date::today();
+
+ $serverDate = $visit->getColumn('firstActionTimestamp');
+ return array(
+ 'date' => $serverDate,
+ 'prettyDate' => Date::factory($serverDate)->getLocalized(Date::DATE_FORMAT_LONG),
+ 'daysAgo' => (int)Date::secondsToDays($today->getTimestamp() - Date::factory($serverDate)->getTimestamp()),
+ 'referrerType' => $visit->getColumn('referrerType'),
+ 'referrerUrl' => $visit->getColumn('referrerUrl') ?: '',
+ 'referralSummary' => self::getReferrerSummaryForVisit($visit),
+ );
+ }
+
+
+ /**
+ * Returns a summary for a visit's referral.
+ *
+ * @param DataTable\Row $visit
+ * @return bool|mixed|string
+ */
+ public static function getReferrerSummaryForVisit($visit)
+ {
+ $referrerType = $visit->getColumn('referrerType');
+ if ($referrerType === false
+ || $referrerType == 'direct'
+ ) {
+ return Piwik::translate('Referrers_DirectEntry');
+ }
+
+ if ($referrerType == 'search') {
+ $referrerName = $visit->getColumn('referrerName');
+
+ $keyword = $visit->getColumn('referrerKeyword');
+ if ($keyword !== false
+ && $keyword != APIReferrers::getKeywordNotDefinedString()
+ ) {
+ $referrerName .= ' (' . $keyword . ')';
+ }
+ return $referrerName;
+ }
+
+ if ($referrerType == 'campaign') {
+
+ $summary = Piwik::translate('Referrers_ColumnCampaign') . ': ' . $visit->getColumn('referrerName');
+ $keyword = $visit->getColumn('referrerKeyword');
+ if (!empty($keyword)) {
+ $summary .= ' - ' . $keyword;
+ }
+
+ return $summary;
+ }
+
+ return $visit->getColumn('referrerName');
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/VisitorDetailsAbstract.php b/plugins/Live/VisitorDetailsAbstract.php
new file mode 100644
index 0000000000..19ae14f685
--- /dev/null
+++ b/plugins/Live/VisitorDetailsAbstract.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live;
+
+use Piwik\DataTable;
+
+/**
+ * Class VisitorDetailsAbstract
+ *
+ * This class can be implemented in a plugin to extend the Live reports, visitor log and profile
+ *
+ * @api
+ */
+abstract class VisitorDetailsAbstract
+{
+ protected $details = array();
+
+ /**
+ * Set details of current visit
+ *
+ * @param array $details
+ */
+ public function setDetails($details)
+ {
+ $this->details = $details;
+ }
+
+ /**
+ * Makes it possible to extend the visitor details returned from API
+ *
+ * **Example**
+ *
+ * public function extendVisitorDetails(&$visitor) {
+ * $crmData = Model::getCRMData($visitor['userid']);
+ *
+ * foreach ($crmData as $prop => $value) {
+ * $visitor[$prop] = $value;
+ * }
+ * }
+ *
+ * @param array $visitor
+ * @return void
+ */
+ public function extendVisitorDetails(&$visitor)
+ {
+ }
+
+ /**
+ * Makes it possible to enrich the action set for a single visit
+ *
+ * **Example**
+ *
+ * public function provideActionsForVisit(&$actions, $visitorDetails) {
+ * $adviews = Model::getAdviews($visitorDetails['visitid']);
+ * $actions += $adviews;
+ * }
+ *
+ * @param array $actions List of action to manipulate
+ * @param array $visitorDetails
+ * @return void
+ */
+ public function provideActionsForVisit(&$actions, $visitorDetails)
+ {
+ }
+
+ /**
+ * Makes it possible to enrich the action set for multiple visits identified by given visit ids
+ *
+ * action set to enrich needs to have the following structure
+ *
+ * $actions = array (
+ * 'idvisit' => array ( list of actions for this visit id ),
+ * 'idvisit' => array ( list of actions for this visit id ),
+ * ...
+ * )
+ *
+ * **Example**
+ *
+ * public function provideActionsForVisitIds(&$actions, $visitIds) {
+ * $adviews = Model::getAdviewsByVisitIds($visitIds);
+ * foreach ($adviews as $idVisit => $adView) {
+ * $actions[$idVisit][] = $adView;
+ * }
+ * }
+ *
+ * @param array $actions action set to enrich
+ * @param array $visitIds list of visit ids
+ */
+ public function provideActionsForVisitIds(&$actions, $visitIds)
+ {
+ }
+
+ /**
+ * Allows filtering the provided actions
+ *
+ * **Example:**
+ *
+ * public function filterActions(&$actions, $visitorDetailsArray) {
+ * foreach ($actions as $idx => $action) {
+ * if ($action['type'] == 'customaction') {
+ * unset($actions[$idx]);
+ * continue;
+ * }
+ * }
+ * }
+ *
+ * @param array $actions
+ * @param array $visitorDetailsArray
+ */
+ public function filterActions(&$actions, $visitorDetailsArray)
+ {
+ }
+
+ /**
+ * Allows extended each action with additional information
+ *
+ * @param array $action
+ * @param array $nextAction
+ * @param array $visitorDetails
+ */
+ public function extendActionDetails(&$action, $nextAction, $visitorDetails)
+ {
+ }
+
+ /**
+ * Called when rendering a single Action
+ *
+ * @param array $action
+ * @param array $previousAction
+ * @param array $visitorDetails
+ * @return string
+ */
+ public function renderAction($action, $previousAction, $visitorDetails)
+ {
+ }
+
+ /**
+ * Called for rendering the tooltip on actions
+ * returned array needs to look like this:
+ * array (
+ * 20, // order id
+ * 'rendered html content'
+ * )
+ *
+ * @param array $action
+ * @param array $visitInfo
+ * @return array
+ */
+ public function renderActionTooltip($action, $visitInfo)
+ {
+ return [];
+ }
+
+ /**
+ * Called when rendering the Icons in visitor log
+ *
+ * @param array $visitorDetails
+ * @return string
+ */
+ public function renderIcons($visitorDetails)
+ {
+ }
+
+ /**
+ * Called when rendering the visitor details in visitor log
+ * returned array needs to look like this:
+ * array (
+ * 20, // order id
+ * 'rendered html content'
+ * )
+ *
+ * **Example**
+ * public function renderVisitorDetails($visitorDetails) {
+ * $view = new View('@MyPlugin/_visitorDetails.twig');
+ * $view->visitInfo = $visitorDetails;
+ * return $view->render();
+ * }
+ *
+ * @param array $visitorDetails
+ * @return array
+ */
+ public function renderVisitorDetails($visitorDetails)
+ {
+ return array();
+ }
+
+ /**
+ * Allows manipulating the visitor profile properties
+ * Will be called when visitor profile is initialized
+ *
+ * **Example**
+ *
+ * public function initProfile($visit, &$profile) {
+ * // initialize properties that will be filled based on visits or actions
+ * $profile['totalActions'] = 0;
+ * $profile['totalActionsOfMyType'] = 0;
+ * }
+ *
+ * @param DataTable $visits
+ * @param array $profile
+ * @return void
+ */
+ public function initProfile($visits, &$profile)
+ {
+ }
+
+ /**
+ * Allows manipulating the visitor profile properties based on included visits
+ * Will be called for every action within the profile
+ *
+ * **Example**
+ *
+ * public function handleProfileVisit($visit, &$profile) {
+ * $profile['totalActions'] += $visit->getColumn('actions');
+ * }
+ *
+ * @param DataTable\Row $visit
+ * @param array $profile
+ * @return void
+ */
+ public function handleProfileVisit($visit, &$profile)
+ {
+ }
+
+ /**
+ * Allows manipulating the visitor profile properties based on included actions
+ * Will be called for every action within the profile
+ *
+ * **Example**
+ *
+ * public function handleProfileAction($action, &$profile)
+ * {
+ * if ($action['type'] != 'myactiontype') {
+ * return;
+ * }
+ *
+ * $profile['totalActionsOfMyType']++;
+ * }
+ *
+ * @param array $action
+ * @param array $profile
+ * @return void
+ */
+ public function handleProfileAction($action, &$profile)
+ {
+ }
+
+ /**
+ * Will be called after iterating over all actions
+ * Can be used to set profile information that requires data that was set while iterating over visits & actions
+ *
+ * **Example**
+ *
+ * public function finalizeProfile($visits, &$profile) {
+ * $profile['isPowerUser'] = false;
+ *
+ * if ($profile['totalActionsOfMyType'] > 20) {
+ * $profile['isPowerUser'] = true;
+ * }
+ * }
+ *
+ * @param DataTable $visits
+ * @param array $profile
+ * @return void
+ */
+ public function finalizeProfile($visits, &$profile)
+ {
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/VisitorProfile.php b/plugins/Live/VisitorProfile.php
index dcf73413af..f4ea6a660c 100644
--- a/plugins/Live/VisitorProfile.php
+++ b/plugins/Live/VisitorProfile.php
@@ -2,7 +2,7 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
@@ -11,27 +11,16 @@ namespace Piwik\Plugins\Live;
use Exception;
use Piwik\DataTable;
-use Piwik\Date;
-use Piwik\Metrics\Formatter;
-use Piwik\Piwik;
-use Piwik\Site;
-use Piwik\Plugins\Referrers\API as APIReferrers;
class VisitorProfile
{
const VISITOR_PROFILE_MAX_VISITS_TO_SHOW = 10;
protected $profile = array();
- private $siteSearchKeywords = array();
- private $continents = array();
- private $countries = array();
- private $cities = array();
- private $pageGenerationTimeTotal = 0;
public function __construct($idSite)
{
$this->idSite = $idSite;
- $this->isEcommerceEnabled = Site::isEcommerceEnabledFor($this->idSite);
}
/**
@@ -44,345 +33,57 @@ class VisitorProfile
*/
public function makeVisitorProfile(DataTable $visits, $visitorId, $segment, $numLastVisits)
{
- $this->initVisitorProfile();
+ $visitorDetailsManipulators = Visitor::getAllVisitorDetailsInstances();
+
+ $this->profile['visitorId'] = $visitorId;
+
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->initProfile($visits, $this->profile);
+ }
/** @var DataTable\Row $visit */
foreach ($visits->getRows() as $visit) {
- ++$this->profile['totalVisits'];
-
- $this->profile['totalVisitDuration'] += $visit->getColumn('visitDuration');
- $this->profile['totalActions'] += $visit->getColumn('actions');
- $this->profile['totalGoalConversions'] += $visit->getColumn('goalConversions');
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->handleProfileVisit($visit, $this->profile);
+ }
- // individual goal conversions are stored in action details
foreach ($visit->getColumn('actionDetails') as $action) {
- $this->handleIfGoalAction($action);
- $this->handleIfEventAction($action);
- $this->handleIfDownloadAction($action);
- $this->handleIfOutlinkAction($action);
- $this->handleIfSiteSearchAction($action);
- $this->handleIfPageViewAction($action);
- $this->handleIfPageGenerationTime($action);
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->handleProfileAction($action, $this->profile);
+ }
}
- $this->handleGeoLocation($visit);
}
- $this->handleGeoLocationCountries();
- $this->handleGeoLocationContinents();
- $this->handleSiteSearches();
- $this->handleAveragePageGenerationTime();
-
- $formatter = new Formatter();
- $this->profile['totalVisitDurationPretty'] = $formatter->getPrettyTimeFromSeconds($this->profile['totalVisitDuration'], true);
-
- $this->handleVisitsSummary($visits);
-
// use N most recent visits for last_visits
$visits->deleteRowsOffset($numLastVisits);
$this->profile['lastVisits'] = $visits;
-
- $this->profile['userId'] = $visit->getColumn('userId');
- $this->profile['visitorId'] = $visitorId;
$this->handleAdjacentVisitorIds($visits, $visitorId, $segment);
- if($this->isEcommerceEnabled()) {
- $this->profile['totalEcommerceRevenue'] = $visit->getColumn('totalEcommerceRevenue');
- $this->profile['totalEcommerceConversions'] = $visit->getColumn('totalEcommerceConversions');
- $this->profile['totalEcommerceItems'] = $visit->getColumn('totalEcommerceItems');
- $this->profile['totalAbandonedCartsRevenue'] = $visit->getColumn('totalAbandonedCartsRevenue');
- $this->profile['totalAbandonedCarts'] = $visit->getColumn('totalAbandonedCarts');
- $this->profile['totalAbandonedCartsItems'] = $visit->getColumn('totalAbandonedCartsItems');
+ foreach ($visitorDetailsManipulators as $instance) {
+ $instance->finalizeProfile($visits, $this->profile);
}
return $this->profile;
}
/**
- * Returns a summary for an important visit. Used to describe the first & last visits of a visitor.
- *
- * @param DataTable\Row $visit
- * @return array
- */
- private function getVisitorProfileVisitSummary($visit)
- {
- $today = Date::today();
-
- $serverDate = $visit->getColumn('firstActionTimestamp');
- return array(
- 'date' => $serverDate,
- 'prettyDate' => Date::factory($serverDate)->getLocalized(Date::DATE_FORMAT_LONG),
- 'daysAgo' => (int)Date::secondsToDays($today->getTimestamp() - Date::factory($serverDate)->getTimestamp()),
- 'referrerType' => $visit->getColumn('referrerType'),
- 'referralSummary' => self::getReferrerSummaryForVisit($visit),
- );
- }
-
-
- /**
- * Returns a summary for a visit's referral.
- *
- * @param DataTable\Row $visit
- * @return bool|mixed|string
- */
- public static function getReferrerSummaryForVisit($visit)
- {
- $referrerType = $visit->getColumn('referrerType');
- if ($referrerType === false
- || $referrerType == 'direct'
- ) {
- return Piwik::translate('Referrers_DirectEntry');
- }
-
- if ($referrerType == 'search') {
- $referrerName = $visit->getColumn('referrerName');
-
- $keyword = $visit->getColumn('referrerKeyword');
- if ($keyword !== false
- && $keyword != APIReferrers::getKeywordNotDefinedString()
- ) {
- $referrerName .= ' (' . $keyword . ')';
- }
- return $referrerName;
- }
-
- if ($referrerType == 'campaign') {
-
- $summary = Piwik::translate('Referrers_ColumnCampaign') . ': ' . $visit->getColumn('referrerName');
- $keyword = $visit->getColumn('referrerKeyword');
- if (!empty($keyword)) {
- $summary .= ' - ' . $keyword;
- }
-
- return $summary;
- }
-
- return $visit->getColumn('referrerName');
- }
-
- private function isEcommerceEnabled()
- {
- return $this->isEcommerceEnabled;
- }
-
- /**
- * @param $action
- */
- private function handleIfEventAction($action)
- {
- if ($action['type'] != 'event') {
- return;
- }
- $this->profile['totalEvents']++;
- }
-
- /**
- * @param $action
- */
- private function handleIfDownloadAction($action)
- {
- if ($action['type'] != 'download') {
- return;
- }
- $this->profile['totalDownloads']++;
- }
-
- /**
- * @param $action
- */
- private function handleIfOutlinkAction($action)
- {
- if ($action['type'] != 'outlink') {
- return;
- }
- $this->profile['totalOutlinks']++;
- }
-
- /**
- * @param $action
- */
- private function handleIfPageViewAction($action)
- {
- if ($action['type'] != 'action') {
- return;
- }
- $this->profile['totalPageViews']++;
- }
-
- private function handleIfGoalAction($action)
- {
- if ($action['type'] != 'goal') {
- return;
- }
- $idGoal = $action['goalId'];
- $idGoalKey = 'idgoal=' . $idGoal;
-
- if (!isset($this->profile['totalConversionsByGoal'][$idGoalKey])) {
- $this->profile['totalConversionsByGoal'][$idGoalKey] = 0;
- }
- ++$this->profile['totalConversionsByGoal'][$idGoalKey];
-
- if (!empty($action['revenue'])) {
- if (!isset($this->profile['totalRevenueByGoal'][$idGoalKey])) {
- $this->profile['totalRevenueByGoal'][$idGoalKey] = 0;
- }
- $this->profile['totalRevenueByGoal'][$idGoalKey] += $action['revenue'];
- }
- }
-
- private function handleIfSiteSearchAction($action)
- {
- if (!isset($action['siteSearchKeyword'])) {
- return;
- }
- $keyword = $action['siteSearchKeyword'];
-
- if (!isset($this->siteSearchKeywords[$keyword])) {
- $this->siteSearchKeywords[$keyword] = 0;
- ++$this->profile['totalSearches'];
- }
- ++$this->siteSearchKeywords[$keyword];
- }
-
- private function handleGeoLocation(DataTable\Row $visit)
- {
- // realtime map only checks for latitude
- $hasLatitude = $visit->getColumn('latitude') !== false;
- if ($hasLatitude) {
- $this->profile['hasLatLong'] = true;
- }
-
- $countryCode = $visit->getColumn('countryCode');
- if (!isset($this->countries[$countryCode])) {
- $this->countries[$countryCode] = 0;
- }
- ++$this->countries[$countryCode];
-
- $continentCode = $visit->getColumn('continentCode');
- if (!isset($this->continents[$continentCode])) {
- $this->continents[$continentCode] = 0;
- }
- ++$this->continents[$continentCode];
-
- if ($countryCode && !array_key_exists($countryCode, $this->cities)) {
- $this->cities[$countryCode] = array();
- }
- $city = $visit->getColumn('city');
- if (!empty($city)) {
- $this->cities[$countryCode][] = $city;
- }
- }
-
- private function handleSiteSearches()
- {
- // sort by visit/action
- arsort($this->siteSearchKeywords);
-
- foreach ($this->siteSearchKeywords as $keyword => $searchCount) {
- $this->profile['searches'][] = array('keyword' => $keyword,
- 'searches' => $searchCount);
- }
- }
-
- private function handleGeoLocationContinents()
- {
- // sort by visit/action
- asort($this->continents);
- foreach ($this->continents as $continentCode => $nbVisits) {
- $this->profile['continents'][] = array('continent' => $continentCode,
- 'nb_visits' => $nbVisits,
- 'prettyName' => \Piwik\Plugins\UserCountry\continentTranslate($continentCode));
- }
- }
-
- private function handleGeoLocationCountries()
- {
- // sort by visit/action
- asort($this->countries);
-
- // transform country/continents/search keywords into something that will look good in XML
- $this->profile['countries'] = $this->profile['continents'] = $this->profile['searches'] = array();
-
- foreach ($this->countries as $countryCode => $nbVisits) {
-
- $countryInfo = array('country' => $countryCode,
- 'nb_visits' => $nbVisits,
- 'flag' => \Piwik\Plugins\UserCountry\getFlagFromCode($countryCode),
- 'prettyName' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode));
- if (!empty($this->cities[$countryCode])) {
- $countryInfo['cities'] = array_unique($this->cities[$countryCode]);
- }
- $this->profile['countries'][] = $countryInfo;
- }
- }
-
- private function initVisitorProfile()
- {
- $this->profile['totalVisits'] = 0;
- $this->profile['totalVisitDuration'] = 0;
- $this->profile['totalActions'] = 0;
- $this->profile['totalEvents'] = 0;
- $this->profile['totalOutlinks'] = 0;
- $this->profile['totalDownloads'] = 0;
- $this->profile['totalSearches'] = 0;
- $this->profile['totalPageViews'] = 0;
- $this->profile['totalPageViewsWithTiming'] = 0;
- $this->profile['totalGoalConversions'] = 0;
- $this->profile['totalConversionsByGoal'] = array();
- $this->profile['hasLatLong'] = false;
-
- if ($this->isEcommerceEnabled()) {
- $this->profile['totalEcommerceRevenue'] = 0;
- $this->profile['totalEcommerceConversions'] = 0;
- $this->profile['totalEcommerceItems'] = 0;
- $this->profile['totalAbandonedCarts'] = 0;
- $this->profile['totalAbandonedCartsRevenue'] = 0;
- $this->profile['totalAbandonedCartsItems'] = 0;
- }
- }
-
- private function handleAveragePageGenerationTime()
- {
- if ($this->profile['totalPageViewsWithTiming']) {
- $this->profile['averagePageGenerationTime'] =
- round($this->pageGenerationTimeTotal / (1000 * $this->profile['totalPageViewsWithTiming']), $precision = 3);
- }
- }
-
- private function handleIfPageGenerationTime($action)
- {
- if (isset($action['generationTimeMilliseconds'])) {
- $this->pageGenerationTimeTotal += $action['generationTimeMilliseconds'];
- ++$this->profile['totalPageViewsWithTiming'];
- }
- }
-
- /**
* @param DataTable $visits
- * @param $visitorId
- * @param $segment
+ * @param $visitorId
+ * @param $segment
*/
private function handleAdjacentVisitorIds(DataTable $visits, $visitorId, $segment)
{
// get visitor IDs that are adjacent to this one in log_visit
// TODO: make sure order of visitor ids is not changed if a returning visitor visits while the user is
// looking at the popup.
- $rows = $visits->getRows();
+ $rows = $visits->getRows();
$latestVisitTime = reset($rows)->getColumn('lastActionDateTime');
- $model = new Model();
- $this->profile['nextVisitorId'] = $model->queryAdjacentVisitorId($this->idSite, $visitorId, $latestVisitTime, $segment, $getNext = true);
- $this->profile['previousVisitorId'] = $model->queryAdjacentVisitorId($this->idSite, $visitorId, $latestVisitTime, $segment, $getNext = false);
- }
-
- /**
- * @param DataTable $visits
- */
- private function handleVisitsSummary(DataTable $visits)
- {
- $rows = $visits->getRows();
- $this->profile['firstVisit'] = $this->getVisitorProfileVisitSummary(end($rows));
- $this->profile['lastVisit'] = $this->getVisitorProfileVisitSummary(reset($rows));
- $this->profile['visitsAggregated'] = count($rows);
+ $model = new Model();
+ $this->profile['nextVisitorId'] = $model->queryAdjacentVisitorId($this->idSite, $visitorId,
+ $latestVisitTime, $segment, $getNext = true);
+ $this->profile['previousVisitorId'] = $model->queryAdjacentVisitorId($this->idSite, $visitorId,
+ $latestVisitTime, $segment, $getNext = false);
}
} \ No newline at end of file
diff --git a/plugins/Live/images/avatar_frame.png b/plugins/Live/images/avatar_frame.png
deleted file mode 100644
index 23eccfd5fb..0000000000
--- a/plugins/Live/images/avatar_frame.png
+++ /dev/null
Binary files differ
diff --git a/plugins/Live/images/paperclip.png b/plugins/Live/images/paperclip.png
deleted file mode 100644
index b38d33caa1..0000000000
--- a/plugins/Live/images/paperclip.png
+++ /dev/null
Binary files differ
diff --git a/plugins/Live/images/visitor_profile_close.png b/plugins/Live/images/visitor_profile_close.png
deleted file mode 100644
index ae132b7b2c..0000000000
--- a/plugins/Live/images/visitor_profile_close.png
+++ /dev/null
Binary files differ
diff --git a/plugins/Live/images/visitor_profile_gradient.png b/plugins/Live/images/visitor_profile_gradient.png
deleted file mode 100644
index ac5068b54d..0000000000
--- a/plugins/Live/images/visitor_profile_gradient.png
+++ /dev/null
Binary files differ
diff --git a/plugins/Live/javascripts/visitorLog.js b/plugins/Live/javascripts/visitorLog.js
index 74393f7ff7..6e66583ae2 100644
--- a/plugins/Live/javascripts/visitorLog.js
+++ b/plugins/Live/javascripts/visitorLog.js
@@ -63,6 +63,10 @@
show: false,
hide: false,
tooltipClass: 'small',
+ content: function() {
+ var title = $(this).attr('title');
+ return $('<a>').text( title ).html().replace(/\n/g, '<br />');
+ },
open: function () {
tooltipIsOpened = true;
},
@@ -72,28 +76,27 @@
});
});
- // Replace duplicated page views by a NX count instead of using too much vertical space
+ // show refresh icon for duplicate page views in a row
$("ol.visitorLog").each(function () {
var prevelement;
var prevhtml;
- var counter = 0;
+ var counter = 0, duplicateCounter = 0;
$(this).find("> li").each(function () {
counter++;
$(this).val(counter);
var current = $(this).html();
+
if (current == prevhtml) {
- var repeat = prevelement.find(".repeat");
- if (repeat.length) {
- repeat.html((parseInt(repeat.html()) + 1) + "x");
- } else {
- prevelement.find('>div').prepend($("<span>2x</span>").attr({'class': 'repeat', 'title': _pk_translate('Live_PageRefreshed')}));
- }
- $(this).hide();
+ $(this).find('>div').prepend($("<span>"+(duplicateCounter+2)+"</span>").attr({'class': 'repeat icon-refresh', 'title': _pk_translate('Live_PageRefreshed')}));
+ duplicateCounter++;
+
} else {
- prevhtml = current;
- prevelement = $(this);
+ duplicateCounter = 0;
}
+ prevhtml = current;
+ prevelement = $(this);
+
var $this = $(this);
var tooltipIsOpened = false;
@@ -104,21 +107,22 @@
}
});
- $this.tooltip({
- track: true,
- show: false,
- hide: false,
- content: function() {
- var title = $(this).attr('title');
- return $('<a>').text( title ).html().replace(/\n/g, '<br />');
- },
- tooltipClass: 'small',
- open: function() { tooltipIsOpened = true; },
- close: function() { tooltipIsOpened = false; }
- });
});
});
+ $("ol.visitorLog > li").tooltip({
+ track: true,
+ show: false,
+ hide: false,
+ content: function() {
+ var title = $(this).attr('title');
+ return $('<a>').text( title ).html().replace(/\n/g, '<br />');
+ },
+ tooltipClass: 'small',
+ open: function() { tooltipIsOpened = true; },
+ close: function() { tooltipIsOpened = false; }
+ });
+
// launch visitor profile on visitor profile link click
this.$element.on('click', '.visitor-log-visitor-profile-link', function (e) {
e.preventDefault();
diff --git a/plugins/Live/javascripts/visitorProfile.js b/plugins/Live/javascripts/visitorProfile.js
index cbe05e0ec7..148ec3b731 100644
--- a/plugins/Live/javascripts/visitorProfile.js
+++ b/plugins/Live/javascripts/visitorProfile.js
@@ -62,9 +62,6 @@
_setupControl: function () {
// focus the popup so it will accept key events
this.$element.focus();
-
- // highlight the first visit
- $('.visitor-profile-visits>li:first-child', this.$element).addClass('visitor-profile-current-visit');
},
_bindEventCallbacks: function () {
@@ -80,20 +77,30 @@
return false;
});
- $element.on('click', '.visitor-profile-more-info>a', function (e) {
+ $element.on('click', '.visitor-profile-toggle-actions', function (e) {
e.preventDefault();
- self._loadMoreVisits();
+ $(this).toggleClass('minimized');
+ if ($(this).hasClass('minimized')) {
+ $('.visitor-profile-actions', $element).slideUp();
+ } else {
+ $('.visitor-profile-actions', $element).slideDown();
+ }
return false;
});
- $element.on('click', '.visitor-profile-see-more-cvars>a', function (e) {
+ $element.on('click', '.visitor-profile-more-info>a', function (e) {
e.preventDefault();
- $('.visitor-profile-extra-cvars', $element).slideToggle();
+ self._loadMoreVisits();
return false;
});
- $element.on('click', '.visitor-profile-visit-title-row', function () {
- self._loadIndividualVisitDetails($('h2', this));
+ $element.on('click', '.visitor-profile-visit-title', function () {
+ $('.visitor-profile-visit-details-extended', $(this).parents('li')).slideToggle();
+ });
+
+ $element.on('click', '.visitor-profile-show-actions', function () {
+ $('.visitor-profile-actions', $(this).parents('li')).slideToggle();
+ return false;
});
$element.on('click', '.visitor-profile-prev-visitor', function (e) {
@@ -140,10 +147,14 @@
});
$element.tooltip({
+ items: '[title],.visitorLogIconWithDetails',
track: true,
show: false,
hide: false,
content: function() {
+ if ($(this).hasClass('visitorLogIconWithDetails')) {
+ return $('<ul>').html($('ul', $(this)).html());
+ }
var title = $(this).attr('title');
return $('<a>').text( title ).html().replace(/\n/g, '<br />');
},
@@ -207,7 +218,8 @@
period: '',
date: '',
visitorId: $element.attr('data-visitor-id'),
- filter_offset: $('.visitor-profile-visits>li', $element).length
+ filter_offset: $('.visitor-profile-visits>li', $element).length,
+ start_number: $('.visitor-profile-visits>li:last', $element).data('number') - 1
}, 'GET');
ajax.setCallback(function (response) {
if (response == "") { // no more visits left
@@ -233,37 +245,6 @@
$('.visitor-profile-more-info', this.$element).html(noMoreSpan);
},
- _loadIndividualVisitDetails: function ($visitElement) {
- var self = this,
- $element = this.$element,
- visitId = $visitElement.attr('data-idvisit');
-
- $('.visitor-profile-avatar .loadingPiwik', $element).css('display', 'inline-block');
- piwikHelper.lazyScrollTo($('.visitor-profile-avatar', $element)[0], 400);
-
- var ajax = new ajaxHelper();
- ajax.addParams({
- module: 'Live',
- action: 'getSingleVisitSummary',
- visitId: visitId,
- idSite: piwik.idSite
- }, 'GET');
- ajax.setCallback(function (response) {
- $('.visitor-profile-avatar .loadingPiwik', $element).hide();
-
- $('.visitor-profile-current-visit', $element).removeClass('visitor-profile-current-visit');
- $visitElement.closest('li').addClass('visitor-profile-current-visit');
-
- var $latestVisitSection = $('.visitor-profile-latest-visit', $element);
- $latestVisitSection
- .html(response)
- .parent()
- .effect('highlight', {color: '#FFFFCB'}, 1200);
- });
- ajax.setFormat('html');
- ajax.send();
- },
-
_loadPreviousVisitor: function () {
this._gotoAdjacentVisitor(this.$element.attr('data-prev-visitor'));
},
diff --git a/plugins/Live/lang/en.json b/plugins/Live/lang/en.json
index dafcf66a92..5ce4712ca3 100644
--- a/plugins/Live/lang/en.json
+++ b/plugins/Live/lang/en.json
@@ -24,9 +24,13 @@
"RealTimeVisitorCount": "Real Time Visitor Count",
"Referrer_URL": "Referrer URL",
"ShowMap": "show map",
+ "ActionsAndDuration": "%1$s actions in %2$s",
"SimpleRealTimeWidget_Message": "%1$s and %2$s in the last %3$s",
"ViewVisitorProfile": "View visitor profile",
"VisitedPages": "Visited pages",
+ "RevisitedPages": "Pages viewed more than once",
+ "ToggleActions": "Toggle visibility of all actions",
+ "TopVisitedPages": "Top visited pages",
"VisitorLog": "Visitor Log",
"VisitorLogDocumentation": "This table shows the latest visits within the selected date range. You can see when a visitor's last visit occurred by hovering over the date of a visit. %1$s If the date range includes today, you can see your visitors real time! %2$s The data displayed here is always live, regardless of whether and how often you are using the archiving cron job.",
"VisitorProfile": "Visitor profile",
diff --git a/plugins/Live/stylesheets/live.less b/plugins/Live/stylesheets/live.less
index 309b93cecc..9be0ca4e75 100644
--- a/plugins/Live/stylesheets/live.less
+++ b/plugins/Live/stylesheets/live.less
@@ -74,7 +74,7 @@
.ui-dialog.ui-widget {
.dataTableVizVisitorLog {
.dataTableFeatures {
- border-bottom: 0px;
+ border-bottom: 0;
}
}
}
@@ -89,7 +89,8 @@
}
ol.visitorLog {
- list-style: decimal inside none;
+ counter-reset: item;
+ list-style-type: none;
}
.truncated-text-line {
@@ -99,15 +100,27 @@ ol.visitorLog {
display:inline-block;
max-width:90%;
overflow: -moz-hidden-unscrollable;
-
- &.event {
- margin-top: 1px;
- margin-right: 15px;
- }
}
-ol.visitorLog li {
+ol.visitorLog > li {
margin-bottom: 7px;
+ line-height: 20px;
+
+ &:before {
+ content: counter(item) " ";
+ counter-increment: item;
+ padding-right: 5px;
+ vertical-align: top;
+ }
+
+ &.more {
+ list-style-type: none;
+ font-weight: bold;
+
+ .icon-info {
+ vertical-align: middle;
+ }
+ }
}
#visitsLive img {
@@ -148,12 +161,13 @@ ol.visitorLog li {
.repeat {
font-weight: bold;
- border: 1px solid @theme-color-text-light;
- border-radius: 3px;
- padding: 2px;
display: block;
- margin: 0px 5px 0px 5px;
+ margin: 5px 5px 5px 0;
float: left;
+
+ &.icon-refresh:before {
+ padding-right: 2px;
+ }
}
.dataTableVizVisitorLog hr {
@@ -201,7 +215,7 @@ ol.visitorLog p {
.dataTableVizVisitorLog {
.card {
- padding: 15px 0px;
+ padding: 15px 0;
font-size: 13px;
text-align: left;
@@ -220,7 +234,7 @@ ol.visitorLog p {
width:100%;
}
- .card {
+ .widget & .card {
&:hover .visitor-log-visitor-profile-link {
display:inline;
@@ -228,6 +242,10 @@ ol.visitorLog p {
}
}
+.visitor-log-datetime {
+ display: block;
+}
+
.visitor-log-page-list {
position:relative;
margin-top: 7px;
@@ -236,46 +254,45 @@ ol.visitorLog p {
a.visitor-log-visitor-profile-link {
z-index: 2;
position:absolute;
- display:none;
right: 15px;
top: 15px;
font-style:italic;
font-size:13px;
background-color: inherit !important;
+ .widget & {
+ display:none;
+ }
+
img {
margin-top: -2px;
margin-bottom: -3px;
}
}
-.visitorLog,.visitor-profile-actions {
+.visitorLog {
> li > div {
- display:inline-block;
- width:90%;
- vertical-align:top;
+ display: inline-block;
+ width: 90%;
+
+ > * {
+ vertical-align: top;
+ }
}
}
.action-list-action-icon {
- float:left;
- margin-right:4px;
+ display: inline;
+ margin: 2px 3px 0 0;
+ max-height: 16px;
- &.event {
- margin-top: 0;
- }
&.outlink {
- margin-top: 4px;
- margin-right: 4px;
- margin-left: 4px;
- }
- &.search {
- margin-right: 4px;
+ margin: 7px 3px 0 0;
}
}
.action-list-url {
- display:block;
+ display: inline-block;
}
.visitorLogIcons {
@@ -288,18 +305,16 @@ a.visitor-log-visitor-profile-link {
}
.visitorLogIcons>span>span>img {
- margin: auto 0 auto 0px;
+ margin: auto 5px auto 0;
}
-.visitorLogIcons .visitorLogIconWithDetails>img {
- margin: auto 5px auto 0;
- width: 16px;
+.visitorLogIconWithDetails>img {
+ margin: auto 5px -2px 0;
height: 16px;
}
.visitorLogIconWithDetails.flag>img {
border: 1px solid lightgray;
- box-sizing: content-box;
}
.visitorLogIcons>span.visitorRank>img {
@@ -316,7 +331,7 @@ a.visitor-log-visitor-profile-link {
.own-visitor-column {
.visitorLogIcons {
.visitorDetails {
- margin-top: 0px;
+ margin-top: 0;
}
.visitorType {
margin-top: 8px;
@@ -327,6 +342,10 @@ a.visitor-log-visitor-profile-link {
.visitorReferrer {
clear:both;
padding-top: 1em;
+
+ * {
+ vertical-align: middle;
+ }
}
.segmentedlog {
diff --git a/plugins/Live/stylesheets/visitor_profile.less b/plugins/Live/stylesheets/visitor_profile.less
index 5622e42f1a..e6161c2559 100644
--- a/plugins/Live/stylesheets/visitor_profile.less
+++ b/plugins/Live/stylesheets/visitor_profile.less
@@ -1,559 +1,440 @@
+.visitor-profile-popup {
+
+ width: 1150px;
+ height: auto;
+ padding: 0;
+
+ > #Piwik_Popover {
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ }
+
+ > .ui-dialog-titlebar {
+ display: none;
+ }
+}
+
.visitor-profile {
- position:relative;
- width:1150px;
- border:1px solid #a19e96;
- border-radius:5px;
- background:url(../images/visitor_profile_background.jpg) repeat;
- box-shadow:5px 5px 5px rgba(0,0,0,0.22);
- text-align:left;
-
- h1 {
- font-size:23px;
- text-shadow:0 1px 0 rgba(255,255,255,1);
- margin:9px 0 0 0;
- padding:0;
- font-weight: normal;
- color: @theme-color-text;
-
- a {
- font-size:12px;
- margin-left:3px;
- }
- }
+ position: relative;
+ width: 1150px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.22);
+ text-align: left;
+ font-size: 13px;
+ line-height: 20px;
- h2 {
- display:inline-block;
- font-size:23px;
- margin:0 0 0 5px;
- padding:15px 17px 15px 22px;
- color:black;
- border: none;
- color: @theme-color-text;
- }
+ body .widget & {
+ width: auto;
+ box-shadow: none;
p {
- margin-left: 0;
- margin-right: 0;
- .font-default(13px, 18px);
- color: @color-silver-l60;
- strong {
- .font-default(13px, 18px);
- color: @theme-color-text;
- font-weight: normal !important;
- }
- span {
- .font-default(13px, 18px);
- }
+ margin: 0;
}
+ }
- p {
- font-size:13px;
- color:#5e5e5c;
- line-height:20px;
- }
+ a {
+ color: #255792;
+ }
+ h1 {
+ line-height: 30px;
+ vertical-align: top;
+ font-size: 23px;
+ margin: 0 0 5px 0;
+ color: @theme-color-text;
+ }
- span.truncated-text-line {
- display:inline-block;
- &.event {
- max-width: 89%;
- }
+ p {
+ color: #5e5e5c;
+
+ body:not(.widgetized) .widget & {
+ padding-bottom: 0;
}
-}
-.visitor-profile-summary,.visitor-profile-important-visits,.visitor-profile-avatar,.visitor-profile-visits-container {
- span, strong {
- display:inline;
- font-size:14px;
- color:#413838;
- line-height:19px;
- padding-left:4px;
+ strong {
+ color: @theme-color-text;
+ font-weight: normal !important;
}
-}
+ }
-.visitor-profile-widget-link {
- color:#5e5e5c;
+ p.alert {
+ margin: 8px 20px 20px 0 !important;
+ font-size: 13px;
+ }
}
-.visitor-profile-export {
- vertical-align: middle;
- margin-top:3px;
+.visitor-profile-options {
+ z-index: 10;
+ position: absolute;
+ right: 6px;
+ height: 28px;
}
-.visitor-profile-close:before {
- content: "\e60a";
+.visitor-profile-toggle-actions,
+.visitor-profile-help,
+.visitor-profile-close {
+ float: right;
+ text-decoration: none !important;
+ margin-right: 5px;
+
+ &:before {
+ color: #000;
+ background-color: #fff;
+ font-size: 16px;
+ line-height: 16px;
+ font-weight: 400;
+ font-family: piwik;
+ padding: 1px;
+ height: 18px;
+ display: block;
+ margin: 5px 0;
+ }
}
.visitor-profile-close {
- z-index: 10;
- position:absolute;
- right:6px;
- top: 4px;
- height:20px;
- width:21px;
+ margin-right: 0;
+
+ &:before {
+ padding: 4.5px;
+ content: "\e60a";
background-color: #d4291f;
- color: #FFFFFF !important;
+ color: #fff;
border-radius: 3px;
font-size: 9px;
- font-weight: 400;
- font-family: piwik;
- text-decoration: none !important;
- text-align: center !important;
- padding: 4.5px;
-}
-
-.visitor-profile a {
- color:#255792;
-}
+ line-height: 9px;
+ }
-.visitor-profile > div {
- width:100%;
+ .widget & {
+ display: none;
+ }
}
-.visitor-profile-info {
- height:auto;
- border-top:2px solid #f6f6f6;
- border-bottom:1px solid #d1cec8;
- border-radius:5px 5px 0 0;
- box-shadow:inset 0 25px 15px -10px #e0e0e0, inset 0 -25px 15px -10px #e0e0e0;
-
- > div { // row
- border-bottom:1px solid #d1cec8;
-
- > div { // columns
- vertical-align:top;
- height:auto;
- display:inline-block;
- }
- }
+.visitor-profile-toggle-actions {
+ &:before {
+ content: "\e62b";
- .visitor-profile-overview { // first column
- width:574px;
- border-left:none;
- margin:0 -3px 0 0;
- border-right:1px solid #d1cec8;
- }
- .visitor-profile-visits-info { // last column
- width:573.5px;
- border-bottom:none;
- margin:0 0 0 -4px;
- border-left:1px solid #d1cec8;
+ .minimized& {
+ content: "\e61c";
}
+ }
}
-.visitor-profile-avatar > div {
- position:relative;
- float:left;
- min-height:145px;
- margin:6px 15px 0 0;
- padding-bottom:4px;
+.visitor-profile-help {
+ &:before {
+ content: "\e61f";
+ }
}
-.visitor-profile-avatar > div:first-child {
- width:166px;
- margin-right:0;
- padding-left:7px;
-
- > .visitor-profile-image-frame {
- width:149px;
- height:154px;
- background:url(../images/avatar_frame.png) no-repeat;
-
- > img { // avatar image
- max-width:122px;
- height:120px;
- margin:11px 0 0 12px;
- }
- }
-
- > img { // paperclip image
- position:absolute;
- top:-20px;
- left:3px;
- z-index:2;
- }
+.visitor-profile-info {
+ overflow: hidden;
}
-.visitor-profile-avatar > div:last-child {
- margin-right:0;
-}
+.visitor-profile-visits-info,
+.visitor-profile-overview {
+ display: inline-block;
+ vertical-align: top;
+ height: auto;
+ border: none;
+ box-sizing: content-box;
+ float: left;
-.visitor-profile-avatar h1 {
- display:inline-block;
-}
+ body:not(.widgetized) .widget & {
+ width: 100%;
+ border: none;
+ margin: 0;
+ }
-.visitor-profile-extra-cvars {
- border-top: 1px solid #d1cec8;
+ body.widgetized .widget & {
+ width: 50%;
+ box-sizing: border-box;
+ }
}
-.visitor-profile-more-info {
- height:18px;
- border-radius:0 0 5px 5px;
- text-align:center;
- padding:0 0 13px;
-
- > a {
- font-size:14px;
- text-decoration:none;
- color:#255792;
- text-shadow:0 1px 0 rgba(255,255,255,1);
- }
-
- > .loadingPiwik {
- padding:0 0 0 4px;
+@media only screen and (max-width: 1000px) {
+ body.widgetized .widget {
+ .visitor-profile-visits-info,
+ .visitor-profile-overview {
+ width: 100%;
}
+ }
}
-.visitor-profile-latest-visit {
- position:relative;
-}
-
-.visitor-profile-latest-visit-column {
- padding-top:6px;
- display:inline-block;
- vertical-align:top;
-}
-
-.visitor-profile-browser {
- margin-left: 5px;
- display:inline-block;
-}
-
-.visitor-profile-os {
- display:inline-block;
+.visitor-profile-widget-link {
+ color: #5e5e5c;
}
-.visitor-profile-latest-visit-column:last-child {
- margin-left:9px;
-}
+.visitor-profile-overview {
+ margin: 0;
+ border-right: 1px solid #d1cec8;
+ padding: 22px 0 0 22px;
+ width: 553px;
-.visitor-profile-avatar ul {
- width:178px;
+ body:not(.widgetized) .widget & {
+ padding: 0 10px;
+ }
}
-.visitor-profile-avatar ul li {
- display:inline-block;
- min-height:24px;
- border-bottom:1px solid #d1cec8;
- width:100%;
+.visitor-profile-visits-info {
+ margin: 28px 0 0 -1px;
+ border-left: 1px solid #d1cec8;
+ width: 574px;
}
-.visitor-profile-id {
- height:24px;
-}
+.visitor-profile-header {
+ overflow: hidden;
+ font-size: 14px;
-.visitor-profile-avatar ul li:last-child {
- border-bottom:none;
-}
+ > div {
+ float: left;
+ }
-.visitor-profile-map {
- padding:0 21px 13px 21px;
+ .visitor-profile-avatar {
+ width: 149px;
+ height: 154px;
- .dataTableFeatures,.no_data {
- display:none !important;
+ > img {
+ max-width: 122px;
+ height: 120px;
}
-}
+ }
-.visitor-profile-map > div {
- border-radius:2px;
- background-color:#fff;
-}
+ .visitor-profile-header-details {
+ width: 376px;
+ }
-.visitor-profile-show-map {
- font-size:13px;
- font-style:italic;
-}
+ .visitor-profile-prev-visitor {
+ color: #7e7363;
+ display: none;
+ position: absolute;
+ right: 100%;
+ top: 0;
+ margin-right: 2px;
+ }
-.visitor-profile-summary,
-.visitor-profile-important-visits,
-.visitor-profile-location,
-.visitor-profile-lifetimevalue
-{
- overflow:hidden;
- padding: 5px 0 16px 22px;
+ .visitor-profile-next-visitor {
+ color: #7e7363;
+ display: none;
+ }
- p {
- font-size:13px;
- line-height: 20px;
- margin-top: 6px;
- margin-right: 1em;
+ &:hover {
+ .visitor-profile-next-visitor,
+ .visitor-profile-prev-visitor {
+ display: inline-block;
}
-}
-.visitor-profile-location img {
- border: 1px solid lightgray;
- box-sizing: content-box;
-}
-
-.visitor-profile-important-visits {
+ }
- > div > div > p:first-child > strong {
- padding-left:0;
- }
+ h1 {
+ display: inline-block;
+ word-wrap: break-word;
+ margin: 0;
+ max-width: 355px;
+ color: #0d0d0d;
+ }
}
-.visitor-profile-summary strong {
- padding-left:0;
+.visitor-profile-headline {
+ position: relative;
+ line-height: 30px;
}
-.visitor-profile-important-visits {
- > div {
- float:left;
- width:265px;
- height:100%;
- }
-
- span {
- padding-left:0;
- }
-}
+.visitor-profile-summary {
+ overflow: hidden;
+ padding: 5px 0 16px 0;
-.visitor-profile-location>p>.loadingPiwik {
- padding:0 0 0 4px;
+ p {
+ margin: 6px 1em 0 0;
+ }
}
-.visitor-profile-pages-visited {
- overflow-y:auto;
- position:relative;
- margin-right:10px;
- border-bottom:none!important;
- padding: 8px 18px 10px 13px;
-
- h1 {
- margin-left:3px;
- }
+.visitor-profile-pages {
+ li {
+ display: block;
+ clear: both;
+ }
}
-.visitor-profile-visits-container {
- overflow-y:auto;
- overflow-x: hidden;
- position:relative;
- margin-right:10px;
- border-bottom:none!important;
- padding:0 18px 0 13px;
-
- .action-list-action-icon {
- margin-right:4px;
- }
-
- ol {
- > li {
- display:block;
- font-size:12px;
- font-weight: normal;
- line-height:10px;
- padding:0 0 10px 13px;
- margin-right: 20px;
- color: @theme-color-text-lighter;
-
- span {
- font-size:13px;
- font-weight:700;
- padding-left:0;
- }
- }
- }
-
- ol.visitor-profile-visits > li {
- margin:0 0 10px 13px;
- padding:0;
-
- > div {
- margin:0 6px 0 6px;
- }
- }
-
- ol.visitor-profile-actions {
- counter-reset:item;
- list-style-type:none;
-
- > li:before {
- content:counter(item) " ";
- counter-increment:item;
- }
- }
-
- ol li ol {
- border-top:1px solid #d1cec8;
- }
-
- ol > li > ol > li {
- margin-left:-12px;
- }
-
- ol li ol li {
- display:block;
- color:#5e5e5c;
- font-size:13px;
- line-height:22px;
- padding-top:1px;
- padding-bottom:1px;
- }
-
- ol li ol li {
- padding-bottom:4px;
- }
-
- ol > li ol li span {
- padding-left:5px;
- }
+.visitor-profile-latest-visit {
- ol > li ol li {
- .action-list-url {
- margin-left:5px;
- line-height:15px;
- font-size:13px;
+ padding-top: 6px;
+
+ .visitorLogIcons {
+ .visitorLogIconWithDetails {
+ display: block;
+ float: left;
+ width: 50%;
+ padding: 6px 0;
+ box-sizing: content-box;
+ height: 16px;
+ position: relative;
+ font-size: 13px;
+
+ img {
+ float: left;
+ margin-left: 2px;
}
- > div > .action-list-url {
- line-height:23px;
+ &.flag img {
+ box-sizing: border-box;
+ margin-left: 0;
}
- }
- ol > li ol li img {
- margin-left:7px;
+ &:after {
+ content: attr(profile-header-text);
+ text-overflow: ellipsis;
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ position: absolute;
+ left: 26px;
+ }
}
- // overrides for _actionsDetails styles
- strong {
- font-size:13px;
- line-height:25px;
+ .visitorType,
+ .visitorTypeIcon {
+ display: none;
}
+ }
}
-.visitor-profile-current-visit {
- background-color:#FAFACF;
-}
+.visitor-profile-id {
+ line-height: 24px;
+ font-size: 13px;
-.visitor-profile-date {
- float:right;
- margin-top:6px;
+ a {
+ color: inherit;
+ }
}
-.visitor-profile-fog {
- height:25px;
- width:546px;
- position:absolute;
- bottom:51px;
- right:28px;
- background:url(../images/visitor_profile_gradient.png) repeat-x;
+.visitor-profile-important-visits > div {
+ float: left;
+ width: 50%;
+ height: 100%;
}
-// popup css
-.visitor-profile-popup {
- width: 1151px;
- height: auto;
- padding: 0;
+.visitor-profile-devices img {
+ height: 16px;
+ float: left;
+ margin-right: 10px;
+ margin-top: 2px;
+}
- > .ui-dialog-titlebar {
- display: none;
- }
+.visitor-profile-location {
+ .loadingPiwik {
+ padding: 0 0 0 4px;
+ border: 0;
+ }
- > #Piwik_Popover {
- padding: 0;
- margin: 0;
- overflow: visible;
- }
+ img {
+ border: 1px solid lightgray;
+ box-sizing: content-box;
+ }
}
-span.visitor-profile-goal-name {
- font-style:italic;
- font-size:14px;
+.visitor-profile-map {
+ padding: 10px 21px 13px 2px;
}
-.visitor-profile-see-more-cvars {
- text-align:center;
+.visitor-profile-visit-title {
+ display: block;
+ font-size: 23px;
+ padding: 13px 15px;
+ border: none;
+ color: @theme-color-text;
+ cursor: pointer;
+ background-color: @color-silver-l95;
- > a {
- display:inline-block;
- color:#5e5e5c;
- }
-}
+ &:hover {
+ background-color: #bfbfbf;
+ }
-.visitor-profile-visit-title-row {
- cursor:pointer;
+ .visitor-profile-date {
+ font-weight: normal;
+ float: right;
+ font-size: 13px;
+ margin-top: 4px;
+ }
}
-.visitor-profile-visit-title-row:hover {
- background-color:#bfbfbf;
-}
+.visitor-profile-visit-details-extended {
+ display: none;
+ padding: 10px 15px;
+ font-size: 13px;
+ line-height: 1.5em;
+ background-color: @color-silver-l95;
-.visitor-profile-avatar .loadingPiwik {
- padding:0;
- margin:0;
+ .visitor-log-datetime {
+ display: none;
+ }
}
-.visitor-profile-visits-info {
- position: relative;
-}
+.visitor-profile-visit-details {
+ padding: 8px 15px;
+ overflow: hidden;
-div.visitor-profile-navigation {
- height:auto;
- min-height:inherit;
- font-size:12px;
- float:none;
- display:block;
- padding:0 0 0 22px;
-}
+ .visitorLogIcons {
+ display: inline;
+ }
-.visitor-profile-header {
- position:relative;
+ .visitorLogIconWithDetails {
+ margin-right: 5px;
+ }
- .visitorProfileHelp {
- display: none;
- &:hover {
- text-decoration: none;
- }
- }
-}
+ .visitorType {
+ display: inline-block;
+ float: left;
+ margin-right: 15px;
+ }
-.visitor-profile-prev-visitor {
- display:none;
- position:absolute;
- right:100%;
- bottom:0;
- margin-right:2px;
-}
+ .visitorDetails {
+ display: inline-block;
+ visibility: hidden;
+ }
-a.visitor-profile-next-visitor,a.visitor-profile-prev-visitor {
- display:none;
- color:#7e7363;
-}
+ &:hover .visitorDetails {
+ visibility: visible;
+ }
-.visitor-profile-avatar:hover {
- .visitor-profile-next-visitor,.visitor-profile-prev-visitor,.visitorProfileHelp {
- display:inline-block;
- }
+ .visitorTypeIcon {
+ display: none;
+ }
}
-.visitor-profile-no-visits {
- color:#999;
- font-size:13px;
+.visitor-profile-visits-info {
+ position: relative;
}
-.visitor-profile-latest-visit-loc {
- display:inline-block;
- position:absolute;
- right:4px;
- top:-24px;
+.visitor-profile-show-actions {
+ float: right;
+ display: inline-block;
+ font-size: 13px;
+ line-height: 24px;
}
-// overrides for the widgetized visitor profile
-.widget .visitor-profile {
- min-width: 100% !important;
+ol.visitor-profile-actions {
+ margin-bottom: 20px;
+
+ li {
+ padding: 0 15px 8px;
+ margin: 0;
p {
- padding-bottom: 0;
+ line-height: 15px;
}
+ }
+}
- .visitor-profile-close {
- display:none;
- }
+.visitor-profile-more-info {
+ height: 18px;
+ text-align: center;
+ padding: 0 0 13px;
+ margin: 5px 0 15px 0;
- .visitor-profile-info {
- > div { // row
- > div { // columns
- min-width:50% !important;
- }
- }
- }
+ .loadingPiwik {
+ padding: 0 0 0 4px;
+ }
+}
+
+.visitor-profile-no-visits {
+ color: #999;
+ font-size: 13px;
}
diff --git a/plugins/Live/templates/_actionCommon.twig b/plugins/Live/templates/_actionCommon.twig
new file mode 100644
index 0000000000..a978588527
--- /dev/null
+++ b/plugins/Live/templates/_actionCommon.twig
@@ -0,0 +1,38 @@
+<li class="{% if action.goalName is defined %}goal{% else %}action{% endif %}"
+ title="{{ postEvent('Live.renderActionTooltip', action, visitInfo) }}">
+ <div>
+ {# Page view / Download / Outlink #}
+ {% if action.pageTitle|default(false) is not empty %}
+ <span class="truncated-text-line">{{ action.pageTitle|rawSafeDecoded }}</span>
+ {% endif %}
+ {% if action.siteSearchKeyword is defined %}
+ {% if action.type == 'search' %}
+ <img src='{{ action.icon }}' title='{{ 'Actions_SubmenuSitesearch'|translate }}'
+ class="action-list-action-icon search">
+ {% endif %}
+ <span class="truncated-text-line">{{ action.siteSearchKeyword|rawSafeDecoded }}</span>
+ {% endif %}
+ {% if action.url is not empty %}
+ {% if action.type == 'action' and action.pageTitle|default(false) is not empty %}<p>{% endif %}
+ {% if action.type == 'download' or action.type == 'outlink' %}
+ <img src='{{ action.icon }}' class="action-list-action-icon {{ action.type }}">
+ {% endif %}
+
+ {% if action.url|trim|lower starts with 'javascript:' or
+ action.url|trim|lower starts with 'vbscript:' or
+ action.url|trim|lower starts with 'data:' %}
+ {{ action.url }}
+ {% else %}
+ <a href="{{ action.url }}" rel="noreferrer" target="_blank"
+ class="action-list-url truncated-text-line">
+ {{ action.url|replace({'http://': '', 'https://': ''}) }}
+ </a>
+ {% endif %}
+ {% if action.type == 'action' and action.pageTitle|default(false) is not empty %}</p>{% endif %}
+ {% elseif action.type != 'search' %}
+ <p>
+ <span>{{ 'General_NotDefined'|translate('Actions_ColumnPageURL'|translate) }}</span>
+ </p>
+ {% endif %}
+ </div>
+</li>
diff --git a/plugins/Live/templates/_actionEcommerce.twig b/plugins/Live/templates/_actionEcommerce.twig
new file mode 100644
index 0000000000..a4b9858105
--- /dev/null
+++ b/plugins/Live/templates/_actionEcommerce.twig
@@ -0,0 +1,54 @@
+<li class="action"
+ title="{{ postEvent('Live.renderActionTooltip', action, visitInfo) }}">
+ <div>
+ {# Ecommerce Abandoned Cart / Ecommerce Order #}
+ <img src="{{ action.icon }}" class="action-list-action-icon"/>
+ {% if action.type == 'ecommerceOrder' %}
+ <strong>{{ 'Goals_EcommerceOrder'|translate }}</strong>
+ <span style='color:#666;'>({{ action.orderId }})</span>
+ {% else %}
+ <strong>{{ 'Goals_AbandonedCart'|translate }}</strong>
+
+ {# TODO: would be nice to have the icons Orders / Cart in the ecommerce log footer #}
+ {% endif %}
+ <p>
+ <span {% if not isWidget %}style='margin-left:22px;'{% endif %}>
+ {% if action.type == 'ecommerceOrder' %}
+ {# spacing is important for tooltip to look nice #}
+ {% set ecommerceOrderTooltip %}{{ 'General_ColumnRevenue'|translate }}: {{ action.revenue|money(visitInfo.idSite)|raw }}
+ {% if action.revenueSubTotal is not empty %} - {{ 'General_Subtotal'|translate }}: {{ action.revenueSubTotal|money(visitInfo.idSite)|raw }}{% endif %}
+
+ {% if action.revenueTax is not empty %} - {{ 'General_Tax'|translate }}: {{ action.revenueTax|money(visitInfo.idSite)|raw }}{% endif %}
+
+ {% if action.revenueShipping is not empty %} - {{ 'General_Shipping'|translate }}: {{ action.revenueShipping|money(visitInfo.idSite)|raw }}{% endif %}
+
+ {% if action.revenueDiscount is not empty %} - {{ 'General_Discount'|translate }}: {{ action.revenueDiscount|money(visitInfo.idSite)|raw }}{% endif %}
+ {% endset %}
+ <abbr title="{{ ecommerceOrderTooltip }}">{{ 'General_ColumnRevenue'|translate }}:
+ {% else %}
+ {% set revenueLeft %}{{ 'General_ColumnRevenue'|translate }}{% endset %}
+ {{ 'Goals_LeftInCart'|translate(revenueLeft) }}:
+ {% endif %}
+ <strong>{{ action.revenue|money(visitInfo.idSite)|raw }}</strong>
+ {% if action.type == 'ecommerceOrder' %}
+ </abbr>
+ {% endif %}, {{ 'General_Quantity'|translate }}: {{ action.items }}
+
+ {# Ecommerce items in Cart/Order #}
+ {% if action.itemDetails is not empty %}
+ <ul style='list-style:square;margin-left:{% if isWidget %}15{% else %}50{% endif %}px;'>
+ {% for product in action.itemDetails %}
+ <li>
+ {{ product.itemSKU }}{% if product.itemName is not empty %}: {{ product.itemName }}{% endif %}
+ {% if product.itemCategory is not empty %} ({{ product.itemCategory }}){% endif %}
+ ,
+ {{ 'General_Quantity'|translate }}: {{ product.quantity }},
+ {{ 'General_Price'|translate }}: {{ product.price|money(visitInfo.idSite)|raw }}
+ </li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </span>
+ </p>
+ </div>
+</li> \ No newline at end of file
diff --git a/plugins/Live/templates/_actionGoal.twig b/plugins/Live/templates/_actionGoal.twig
new file mode 100644
index 0000000000..dadfc566e8
--- /dev/null
+++ b/plugins/Live/templates/_actionGoal.twig
@@ -0,0 +1,11 @@
+<li class="action"
+ title="{{ postEvent('Live.renderActionTooltip', action, visitInfo) }}">
+ <div>
+ {# Goal conversion #}
+ <img src="{{ action.icon }}" class="action-list-action-icon" />
+ <strong>{{ action.goalName }}</strong>
+ {% if action.revenue > 0 %}, {{ 'General_ColumnRevenue'|translate }}:
+ <strong>{{ action.revenue|money(visitInfo.idSite)|raw }}</strong>
+ {% endif %}
+ </div>
+</li> \ No newline at end of file
diff --git a/plugins/Live/templates/_actionTooltip.twig b/plugins/Live/templates/_actionTooltip.twig
new file mode 100644
index 0000000000..b0e885a1ae
--- /dev/null
+++ b/plugins/Live/templates/_actionTooltip.twig
@@ -0,0 +1,8 @@
+{{ action.serverTimePretty }}{% if action.url is defined and action.url|trim|length %}
+
+{{ action.url }}{% endif %}{%- if action.generationTime is defined %}
+
+{{ 'General_ColumnGenerationTime'|translate }}: {{ action.generationTime|raw }}{% endif %}
+{%- if action.timeSpentPretty is defined %}
+
+{{ 'General_TimeOnPage'|translate }}: {{ action.timeSpentPretty|raw }}{% endif -%} \ No newline at end of file
diff --git a/plugins/Live/templates/_actionsList.twig b/plugins/Live/templates/_actionsList.twig
index a36a9da66d..1f6ff3e7c9 100644
--- a/plugins/Live/templates/_actionsList.twig
+++ b/plugins/Live/templates/_actionsList.twig
@@ -1,133 +1,14 @@
{% set previousAction = false %}
{% for action in actionDetails %}
- {% set customVariablesTooltip %}
- {% if action.customVariables is defined %}
- {{ 'CustomVariables_CustomVariables'|translate }}:
- {% for id,customVariable in action.customVariables %}
- {% set name = 'customVariablePageName' ~ id %}
- {% set value = 'customVariablePageValue' ~ id %}
- - {{ customVariable[name]|raw }} {% if customVariable[value]|length > 0 %} = {{ customVariable[value]|raw }}{% endif %}
- {# line break above is important #}
- {% endfor %}
- {% endif %}
- {% endset %}
+ {{ postEvent('Live.renderAction', action, previousAction, visitInfo) }}
- <li class="{% if action.goalName is defined %}goal{% else %}action{% endif %}"
- title="{{ action.serverTimePretty }}{% if action.url is defined and action.url|trim|length %}
+{% set previousAction = action %}
+{% endfor %}
-{{ action.url }}{% endif %}{% if customVariablesTooltip|trim|length %}
-
-{{ customVariablesTooltip|trim }}{% endif -%}
- {%- if action.generationTime is defined %}
-
-{{ 'General_ColumnGenerationTime'|translate }}: {{ action.generationTime|raw }}{% endif %}
- {%- if action.timeSpentPretty is defined %}
-
-{{ 'General_TimeOnPage'|translate }}: {{ action.timeSpentPretty|raw }}{% endif -%}">
- <div>
- {% if action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %}
- {# Ecommerce Abandoned Cart / Ecommerce Order #}
- <img src="{{ action.icon }}"/>
- {% if action.type == 'ecommerceOrder' %}
- <strong>{{ 'Goals_EcommerceOrder'|translate }}</strong>
- <span style='color:#666;'>({{ action.orderId }})</span>
- {% else %}
- <strong>{{'Goals_AbandonedCart'|translate}}</strong>
-
- {# TODO: would be nice to have the icons Orders / Cart in the ecommerce log footer #}
- {% endif %}
- <p>
- <span {% if not isWidget %}style='margin-left:20px;'{% endif %}>
- {% if action.type == 'ecommerceOrder' %}
-{# spacing is important for tooltip to look nice #}
-{% set ecommerceOrderTooltip %}{{ 'General_ColumnRevenue'|translate }}: {{ action.revenue|money(clientSideParameters.idSite)|raw }}
-{% if action.revenueSubTotal is not empty %} - {{ 'General_Subtotal'|translate }}: {{ action.revenueSubTotal|money(clientSideParameters.idSite)|raw }}{% endif %}
-
-{% if action.revenueTax is not empty %} - {{ 'General_Tax'|translate }}: {{ action.revenueTax|money(clientSideParameters.idSite)|raw }}{% endif %}
-
-{% if action.revenueShipping is not empty %} - {{ 'General_Shipping'|translate }}: {{ action.revenueShipping|money(clientSideParameters.idSite)|raw }}{% endif %}
-
-{% if action.revenueDiscount is not empty %} - {{ 'General_Discount'|translate }}: {{ action.revenueDiscount|money(clientSideParameters.idSite)|raw }}{% endif %}
-{% endset %}
- <abbr title="{{ ecommerceOrderTooltip }}">{{ 'General_ColumnRevenue'|translate }}:
- {% else %}
- {% set revenueLeft %}{{ 'General_ColumnRevenue'|translate }}{% endset %}
- {{ 'Goals_LeftInCart'|translate(revenueLeft) }}:
- {% endif %}
- <strong>{{ action.revenue|money(clientSideParameters.idSite)|raw }}</strong>
- {% if action.type == 'ecommerceOrder' %}
- </abbr>
- {% endif %}, {{ 'General_Quantity'|translate }}: {{ action.items }}
-
- {# Ecommerce items in Cart/Order #}
- {% if action.itemDetails is not empty %}
- <ul style='list-style:square;margin-left:{% if isWidget %}15{% else %}50{% endif %}px;'>
- {% for product in action.itemDetails %}
- <li>
- {{ product.itemSKU }}{% if product.itemName is not empty %}: {{ product.itemName }}{% endif %}
- {% if product.itemCategory is not empty %} ({{ product.itemCategory }}){% endif %}
- ,
- {{ 'General_Quantity'|translate }}: {{ product.quantity }},
- {{ 'General_Price'|translate }}: {{ product.price|money(clientSideParameters.idSite)|raw }}
- </li>
- {% endfor %}
- </ul>
- {% endif %}
- </span>
- </p>
- {% elseif action.goalName is not defined%}
- {# Page view / Download / Outlink / Event #}
- {% if action.pageTitle|default(false) is not empty %}
- <span class="truncated-text-line">{{ action.pageTitle|rawSafeDecoded }}</span>
- {% endif %}
- {% if action.siteSearchKeyword is defined %}
- {% if action.type == 'search' %}
- <img src='{{ action.icon }}' title='{{ 'Actions_SubmenuSitesearch'|translate }}' class="action-list-action-icon search">
- {% endif %}
- <span class="truncated-text-line">{{ action.siteSearchKeyword|rawSafeDecoded }}</span>
- {% endif %}
- {% if action.eventCategory|default(false) is not empty %}
- <img src='{{ action.icon }}' title='{{ 'Events_Event'|translate }}' class="action-list-action-icon event">
- <span class="truncated-text-line event">{{ action.eventCategory|rawSafeDecoded }} - {{ action.eventAction|rawSafeDecoded }} {% if action.eventName is defined %}- {{ action.eventName|rawSafeDecoded }}{% endif %} {% if action.eventValue is defined %}[{{ action.eventValue }}]{% endif %}</span>
- {% endif %}
- {% if action.url is not empty %}
- {% if action.type == 'action' and action.pageTitle|default(false) is not empty %}<p>{% endif %}
- {% if action.type == 'download' or action.type == 'outlink' %}
- <img src='{{ action.icon }}' class="action-list-action-icon {{ action.type }}">
- {% endif %}
-
- {% if action.eventCategory|default(false) is not empty
- and previousAction.url|default(false) == action.url %}
- {# For events, do not show (url) if the Event URL is the same as the URL last displayed #}
- {% else %}
- {% if action.url|trim|lower starts with 'javascript:' or
- action.url|trim|lower starts with 'vbscript:' or
- action.url|trim|lower starts with 'data:' %}
- {{ action.url }}
- {% else %}
- <a href="{{ action.url }}" rel="noreferrer" target="_blank" class="{% if action.eventCategory|default(false) is empty %}action-list-url{# don't put URL on new line for events #}{% endif %} truncated-text-line"
- {% if overrideLinkStyle is not defined or overrideLinkStyle %}style="text-decoration:underline;"{% endif %}>
- {{ action.url|replace({'http://': '', 'https://': ''}) }}
- </a>
- {% endif %}
- {% endif %}
- {% if action.type == 'action' and action.pageTitle|default(false) is not empty %}</p>{% endif %}
- {% elseif action.type != 'search' and action.type != 'event' %}
- <p>
- <span>{{ clientSideParameters.pageUrlNotDefined }}</span>
- </p>
- {% endif %}
- {% else %}
- {# Goal conversion #}
- <img src="{{ action.icon }}" />
- <strong>{{ action.goalName }}</strong>
- {% if action.revenue > 0 %}, {{ 'General_ColumnRevenue'|translate }}:
- <strong>{{ action.revenue|money(clientSideParameters.idSite)|raw }}</strong>
- {% endif %}
- {% endif %}
- </div>
+{% if visitInfo.truncatedActionsCount is defined %}
+ <li class="more">
+ <span class="icon-info"></span>
+ {{ 'Live_MorePagesNotDisplayed'|translate }}
</li>
-
- {% set previousAction = action %}
-{% endfor %} \ No newline at end of file
+{% endif %} \ No newline at end of file
diff --git a/plugins/Live/templates/_dataTableViz_visitorLog.twig b/plugins/Live/templates/_dataTableViz_visitorLog.twig
index 5281f9974f..eb09ee8730 100644
--- a/plugins/Live/templates/_dataTableViz_visitorLog.twig
+++ b/plugins/Live/templates/_dataTableViz_visitorLog.twig
@@ -2,111 +2,6 @@
{% set cycleIndex=0 %}
{% for visitor in dataTable.getRows() %}
- {% set visitHasEcommerceActivity = visitor.getColumn('visitEcommerceStatusIcon') %}
- {% set breakBeforeVisitorRank = (visitHasEcommerceActivity and visitor.getColumn('visitorTypeIcon')) ? true : false %}
- {% set visitorColumnContent %}
-
- <span class="visitorLogIcons">
-
- <span class="visitorDetails">
- {% if visitor.getColumn('browserIcon') %}
- <span class="visitorLogIconWithDetails">
- <img src="{{ visitor.getColumn('browserIcon') }}"/>
- <ul class="details">
- <li>{{ 'DevicesDetection_ColumnBrowser'|translate }}: {{ visitor.getColumn('browser') }}</li>
- <li>{{ 'DevicesDetection_BrowserEngine'|translate }}: {{ visitor.getColumn('browserFamily') }}</li>
- {% if visitor.getColumn('pluginsIcons')|length > 0 %}
- <li>
- {{ 'General_Plugins'|translate }}:
- {% for pluginIcon in visitor.getColumn('pluginsIcons') %}
- <img width="16px" height="16px" src="{{ pluginIcon.pluginIcon }}" alt="{{ pluginIcon.pluginName|capitalize(true) }}"/>
- {% endfor %}
- </li>
- {% endif %}
- </ul>
- </span>
- {% endif %}
- {% if visitor.getColumn('operatingSystemIcon') %}
- <span class="visitorLogIconWithDetails">
- <img src="{{ visitor.getColumn('operatingSystemIcon') }}"/>
- <ul class="details">
- <li>{{ 'DevicesDetection_ColumnOperatingSystem'|translate }}: {{ visitor.getColumn('operatingSystem') }}</li>
- </ul>
- </span>
- {% endif %}
- {% if visitor.getColumn('deviceTypeIcon') %}
- <span class="visitorLogIconWithDetails">
- <img src="{{ visitor.getColumn('deviceTypeIcon') }}"/>
- <ul class="details">
- <li>{{ 'DevicesDetection_DeviceType'|translate }}: {{ visitor.getColumn('deviceType') }}</li>
- {% if visitor.getColumn('deviceBrand') %}<li>{{ 'DevicesDetection_DeviceBrand'|translate }}: {{ visitor.getColumn('deviceBrand') }}</li>{% endif %}
- {% if visitor.getColumn('deviceModel') %}<li>{{ 'DevicesDetection_DeviceModel'|translate }}: {{ visitor.getColumn('deviceModel') }}</li>{% endif %}
- {% if visitor.getColumn('resolution') %}<li>{{ 'Resolution_ColumnResolution'|translate }}: {{ visitor.getColumn('resolution') }}</li>{% endif %}
- </ul>
- </span>
- {% endif %}
- </span>
-
- <span class="visitorType">
- {# Goals, and/or Ecommerce activity #}
- {% if visitor.getColumn('visitConverted') %}
- <span title="{{ 'General_VisitConvertedNGoals'|translate(visitor.getColumn('goalConversions')) }}" class='visitorRank visitorLogTooltip'
- {% if not displayVisitorsInOwnColumn or breakBeforeVisitorRank %}style="margin-left:0;"{% endif %}>
- <img src="{{ visitor.getColumn('visitConvertedIcon') }}"/>
- <span class='hash'>#</span>
- {{ visitor.getColumn('goalConversions') }}
- {% if visitHasEcommerceActivity %}
- &nbsp;
- <img src="{{ visitor.getColumn('visitEcommerceStatusIcon') }}" class='visitorLogTooltip' title="{{ visitor.getColumn('visitEcommerceStatus') }}"/>
- {% endif %}
- </span>
- {# Ecommerce activity only (no goal) #}
- {% elseif visitHasEcommerceActivity %}
- <img class="visitorLogTooltip" src="{{ visitor.getColumn('visitEcommerceStatusIcon') }}" title="{{ visitor.getColumn('visitEcommerceStatus') }}"/>
- {% endif %}
- </span>
- </span>
-
- {% endset %}
-
- {% set referrerContent %}
- <div class="visitorReferrer">
- {% if visitor.getColumn('referrerType') == 'website' %}
- {{ 'Referrers_ColumnWebsite'|translate }}:
- <a href="{{ visitor.getColumn('referrerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitor.getColumn('referrerUrl') }}"
- style="text-decoration:underline;">
- {{ visitor.getColumn('referrerName') }}
- </a>
- {% endif %}
- {% if visitor.getColumn('referrerType') == 'campaign' %}
- {{ 'Referrers_ColumnCampaign'|translate }}: {{ visitor.getColumn('referrerName') }}
- {% if visitor.getColumn('referrerKeyword') is not empty %} - {{ visitor.getColumn('referrerKeyword') }}{% endif %}
- {% endif %}
- {% if visitor.getColumn('referrerType') == 'search' %}
- {%- set keywordNotDefined = 'General_NotDefined'|translate('General_ColumnKeyword'|translate) -%}
- {%- set showKeyword = visitor.getColumn('referrerKeyword') is not empty and visitor.getColumn('referrerKeyword') != keywordNotDefined -%}
- {% if visitor.getColumn('searchEngineIcon') %}
- <img src="{{ visitor.getColumn('searchEngineIcon') }}" alt="{{ visitor.getColumn('referrerName') }}"/>
- {% endif %}
- <span {% if not showKeyword %}title="{{ keywordNotDefined }}" class="visitorLogTooltip"{% endif %}>{{ visitor.getColumn('referrerName') }}</span>
- {% if showKeyword %}{{ 'Referrers_Keywords'|translate }}:
- <a href="{{ visitor.getColumn('referrerUrl') }}" rel="noreferrer" target="_blank" style="text-decoration:underline;">
- "{{ visitor.getColumn('referrerKeyword') }}"</a>
- {% endif %}
- {% set keyword %}{{ visitor.getColumn('referrerKeyword') }}{% endset %}
- {% set searchName %}{{ visitor.getColumn('referrerName') }}{% endset %}
- {% set position %}#{{ visitor.getColumn('referrerKeywordPosition') }}{% endset %}
- {% if visitor.getColumn('referrerKeywordPosition') %}
- <span title='{{ 'Live_KeywordRankedOnSearchResultForThisVisitor'|translate(keyword,position,searchName) }}' class='visitorRank visitorLogTooltip'>
- <span class='hash'>#</span>
- {{ visitor.getColumn('referrerKeywordPosition') }}
- </span>
- {% endif %}
- {% endif %}
- {% if visitor.getColumn('referrerType') == 'direct' %}{{ 'Referrers_DirectEntry'|translate }}{% endif %}
- </div>
- {% endset %}
-
{% set visitorRow %}
<div class="card row hoverable">
@@ -119,80 +14,12 @@
{% set cycleIndex=cycleIndex+1 %}
<div class="col s12 m{% if displayVisitorsInOwnColumn %}3{% else %}4{% endif %}">
- <strong class="visitorLogTooltip" title="{% if visitor.getColumn('visitorType')=='new' %}{{ 'General_NewVisitor'|translate }}{% else %}{{ 'Live_VisitorsLastVisit'|translate(visitor.getColumn('daysSinceLastVisit')) }}{% endif %}">
- {{ visitor.getColumn('serverDatePrettyFirstAction') }}
- {% if isWidget %}<br/>{% else %}-{% endif %} {{ visitor.getColumn('serverTimePrettyFirstAction') }}</strong>
- {% if visitor.getColumn('visitIp') is not empty %}
- <br/>
- <span class="visitorLogTooltip" title="{% if visitor.getColumn('userId') is not empty %}{{ 'General_UserId'|translate }}: {{ visitor.getColumn('userId')|raw }}{% endif %}
-
-{% if visitor.getColumn('visitorId') is not empty %}{{ 'General_VisitorID'|translate }}: {{ visitor.getColumn('visitorId') }}{% endif -%}
-{%- if visitor.getColumn('latitude') or visitor.getColumn('longitude') %}
-
-{{ visitor.getColumn('location') }}
-
-GPS (lat/long): {{ visitor.getColumn('latitude') }},{{ visitor.getColumn('longitude') }}{% endif %}">
- IP: {{ visitor.getColumn('visitIp') }}
- {% if visitor.getColumn('userId') is not empty %}<br/><br/>{{ visitor.getColumn('userId')|raw }}{% endif %}
-
- </span>{% endif %}
-
- {% if visitor.getColumn('provider') %}
- <br/>
- {{ 'Provider_ColumnProvider'|translate }}:
- {% if visitor.getColumn('providerUrl') %}
- <a href="{{ visitor.getColumn('providerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitor.getColumn('providerName') }} {{ visitor.getColumn('providerUrl') }}" style="text-decoration:underline;">
- {% endif -%}
- {{ visitor.getColumn('providerName') }}
- {%- if visitor.getColumn('providerUrl') %}</a>{% endif %}
- {% endif %}
- {% if visitor.getColumn('visitorTypeIcon') or visitor.getColumn('countryFlag') %}
- <br/>
- {% endif %}
- {% if visitor.getColumn('visitorTypeIcon') %}
- <span class="visitorLogIconWithDetails">
- <img src="{{ visitor.getColumn('visitorTypeIcon') }}"/>
- <ul class="details">
- <li>{{ 'General_ReturningVisitor'|translate }} - {{ 'General_NVisits'|translate(visitor.getColumn('visitCount')) }}</li>
- </ul>
- </span>
- {% endif %}
- {% if visitor.getColumn('countryFlag') %}
- <span class="visitorLogIconWithDetails flag">
-
- <img height="16px" src="{{ visitor.getColumn('countryFlag') }}"/>
- {% if visitor.getColumn('city') %}{{ visitor.getColumn('city')|rawSafeDecoded }}{% endif -%}
- {%- if visitor.getColumn('region') %}{% if visitor.getColumn('city') %}, {% endif %}{{ visitor.getColumn('region')|rawSafeDecoded }}{% endif %}
-
- <ul class="details">
- <li>{{ 'UserCountry_Country'|translate }}: {{ visitor.getColumn('country') }}</li>
- {% if visitor.getColumn('region') %}<li>{{ 'UserCountry_Region'|translate }}: {{ visitor.getColumn('region') }}</li>{% endif %}
- {% if visitor.getColumn('city') %}<li>{{ 'UserCountry_City'|translate }}: {{ visitor.getColumn('city') }}</li>{% endif %}
- </ul>
- </span>
- {% endif %}
- {% if visitor.getColumn('customVariables') %}
- <br/>
- {% for id,customVariable in visitor.getColumn('customVariables') %}
- {% set name='customVariableName' ~ id %}
- {% set value='customVariableValue' ~ id %}
- <br/>
- <acronym class="visitorLogTooltip" title="{{ 'CustomVariables_CustomVariables'|translate }} (index {{ id }})">
- {{ customVariable[name]|truncate(30) }}
- </acronym>
- {% if customVariable[value]|length > 0 %}: {{ customVariable[value]|truncate(50) }}{% endif %}
- {% endfor %}
- {% endif %}
- {% if not displayVisitorsInOwnColumn %}
- <br/>
- {{ visitorColumnContent }}
- {% endif %}
- {{ referrerContent }}
+ {{ postEvent('Live.renderVisitorDetails', visitor) }}
</div>
{% if displayVisitorsInOwnColumn %}
<div class="col s12 m2 own-visitor-column">
- {{ visitorColumnContent }}
+ {{ postEvent('Live.renderVisitorIcons', visitor) }}
</div>
{% endif %}
@@ -200,8 +27,12 @@ GPS (lat/long): {{ visitor.getColumn('latitude') }},{{ visitor.getColumn('longit
{{ postEvent('Live.visitorLogViewBeforeActionsInfo', visitor) }}
<strong>
- {{ visitor.getColumn('actionDetails')|length }}
- {% if visitor.getColumn('actionDetails')|length <= 1 %}
+ {% set actionCount = visitor.getColumn('actionDetails')|length %}
+ {% if visitor.truncatedActionsCount is defined %}
+ {% set actionCount = actionCount + visitor.truncatedActionsCount %}
+ {% endif %}
+ {{ actionCount }}
+ {% if actionCount <= 1 %}
{{ 'General_Action'|translate }}
{% else %}
{{ 'General_Actions'|translate }}
@@ -211,7 +42,7 @@ GPS (lat/long): {{ visitor.getColumn('latitude') }},{{ visitor.getColumn('longit
<div class="visitor-log-page-list">
<ol class='visitorLog'>
- {% include "@Live/_actionsList.twig" with {'actionDetails': visitor.getColumn('actionDetails')} %}
+ {% include "@Live/_actionsList.twig" with {'actionDetails': visitor.getColumn('actionDetails'), 'visitInfo': visitor} %}
</ol>
</div>
{{ postEvent('Live.visitorLogViewAfterActionsInfo', visitor) }}
diff --git a/plugins/Live/templates/_profileSummary.twig b/plugins/Live/templates/_profileSummary.twig
new file mode 100644
index 0000000000..b10c5c016b
--- /dev/null
+++ b/plugins/Live/templates/_profileSummary.twig
@@ -0,0 +1,38 @@
+{% set pageviewDetails %}
+ {{ visitorData.totalUniquePageViews }} {{ 'General_ColumnUniquePageviews'|translate }}, {{ visitorData.totalRevisitedPages }} {{ 'Actions_RevisitedPages'|translate }}
+{% endset %}
+
+<div class="visitor-profile-summary visitor-profile-resume">
+ <h1>{{ 'General_Summary'|translate }}</h1>
+ <div>
+ {% if visitorData.totalPageViews != visitorData.totalActions %}
+ {% set actionDetails = [] %}
+ {% if visitorData.totalPageViews > 0 %}{% set actionDetails = actionDetails|merge(['<span title="' ~ pageviewDetails ~ '">' ~ visitorData.totalPageViews ~ ' ' ~ 'General_ColumnPageviews'|translate ~ '</span>']) %}{% endif %}
+ {% if visitorData.totalEvents > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalEvents ~ ' ' ~ 'Events_Events'|translate]) %}{% endif %}
+ {% if visitorData.totalDownloads > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalDownloads ~ ' ' ~ 'General_Downloads'|translate]) %}{% endif %}
+ {% if visitorData.totalOutlinks > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalOutlinks ~ ' ' ~ 'General_Outlinks'|translate]) %}{% endif %}
+ {% if visitorData.totalSearches > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalSearches ~ ' ' ~ 'Actions_ColumnSearches'|translate]) %}{% endif %}
+ <p>{{ 'Live_VisitSummaryWithActionDetails'|translate('<strong>' ~ visitorData.totalVisitDurationPretty ~ '</strong>', '', '', '<strong>' ~ visitorData.totalActions, '</strong>', actionDetails|join(', ') , '<strong>' ~ visitorData.totalVisits, '</strong>')|raw }}</p>
+ {% else %}
+ <p>{{ 'Live_VisitSummary'|translate('<strong>' ~ visitorData.totalVisitDurationPretty ~ '</strong>', '', '', '<strong title="' ~ pageviewDetails ~ '">' ~ visitorData.totalActions, '</strong>', '<strong>' ~ visitorData.totalVisits, '</strong>')|raw }}</p>
+ {% endif %}
+ <p>{% if visitorData.totalGoalConversions %}<strong>{% endif %}{{ 'Live_ConvertedNGoals'|translate(visitorData.totalGoalConversions) }}{% if visitorData.totalGoalConversions %}</strong>{% endif %}
+ {%- if visitorData.totalGoalConversions %} (
+ {%- for idGoal, totalConversions in visitorData.totalConversionsByGoal -%}
+ {%- set idGoal = idGoal[7:] -%}
+ {%- if not loop.first %}, {% endif -%}{{- totalConversions }} {{ goals[idGoal]['name'] -}}
+ {%- endfor -%}
+ ){% endif %}.</p>
+ {% if visitorData.totalSearches|default(0) %}
+ <p>
+ {{ 'Actions_WidgetSearchKeywords'|translate }}:
+ {%- for entry in visitorData.searches %} <strong title="{% if entry.searches == 1 %}{{ 'Actions_OneSearch'|translate }}{% else %}{{ 'UserCountryMap_Searches'|translate(entry.searches) }}{% endif %}">{{ entry.keyword }}</strong>{% if not loop.last %},{% endif %}{% endfor %}
+ </p>
+ {% endif %}
+ {% if visitorData.averagePageGenerationTime is defined %}
+ <p title="{{ 'Live_CalculatedOverNPageViews'|translate(visitorData.totalPageViewsWithTiming) }}">
+ {{ 'Live_AveragePageGenerationTime'|translate('<strong>' ~ visitorData.averagePageGenerationTime ~ 's</strong>')|raw }}
+ </p>
+ {% endif %}
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/Live/templates/_profileSummaryVisits.twig b/plugins/Live/templates/_profileSummaryVisits.twig
new file mode 100644
index 0000000000..a5c247ddf6
--- /dev/null
+++ b/plugins/Live/templates/_profileSummaryVisits.twig
@@ -0,0 +1,39 @@
+<div class="visitor-profile-summary visitor-profile-important-visits">
+ {%- set keywordNotDefined = 'General_NotDefined'|translate('General_ColumnKeyword'|translate) -%}
+ <div>
+ <h1>{% if visitorData.visitsAggregated == 100 %}{{ 'General_Visit'|translate }}# 100{% else %}{{ 'Live_FirstVisit'|translate }}{% endif %}</h1>
+ <div>
+ <p><strong>{{ visitorData.firstVisit.prettyDate }}</strong>&nbsp;- {{ 'UserCountryMap_DaysAgo'|translate(visitorData.firstVisit.daysAgo) }}</p>
+ <p>
+ {{ 'General_FromReferrer'|translate }} <strong {% if visitorData.firstVisit.referrerType == 'search' and '(' not in visitorData.firstVisit.referralSummary %}title="{{ keywordNotDefined }}"{% endif %}>
+ {%- if visitorData.firstVisit.referrerType == 'website' %}
+ <a href="{{ visitorData.firstVisit.referrerUrl }}" target="_blank">
+ {{ visitorData.firstVisit.referralSummary }}
+ </a>
+ {% else %}
+ {{ visitorData.firstVisit.referralSummary }}
+ {% endif %}
+ </strong>
+ </p>
+ </div>
+ </div>
+ {% if visitorData.lastVisits.getRowsCount() != 1 %}
+ <div>
+ <h1>{{ 'Live_LastVisit'|translate }}</h1>
+ <div>
+ <p><strong>{{ visitorData.lastVisit.prettyDate }}</strong>&nbsp;- {{ 'UserCountryMap_DaysAgo'|translate(visitorData.lastVisit.daysAgo) }}</p>
+ <p>
+ {{ 'General_FromReferrer'|translate }} <strong {% if visitorData.lastVisit.referrerType == 'search' and '(' not in visitorData.lastVisit.referralSummary %}title="{{ keywordNotDefined }}"{% endif %}>
+ {%- if visitorData.lastVisit.referrerType == 'website' %}
+ <a href="{{ visitorData.lastVisit.referrerUrl }}" target="_blank">
+ {{ visitorData.lastVisit.referralSummary }}
+ </a>
+ {% else %}
+ {{ visitorData.lastVisit.referralSummary }}
+ {% endif %}
+ </strong>
+ </p>
+ </div>
+ </div>
+ {% endif %}
+</div> \ No newline at end of file
diff --git a/plugins/Live/templates/_visitorDetails.twig b/plugins/Live/templates/_visitorDetails.twig
new file mode 100644
index 0000000000..63edc4fd80
--- /dev/null
+++ b/plugins/Live/templates/_visitorDetails.twig
@@ -0,0 +1,17 @@
+<strong class="visitor-log-datetime visitorLogTooltip" title="{% if visitInfo.getColumn('visitorType')=='new' %}{{ 'General_NewVisitor'|translate }}{% else %}{{ 'Live_VisitorsLastVisit'|translate(visitInfo.getColumn('daysSinceLastVisit')) }}{% endif %}">
+ {{ visitInfo.getColumn('serverDatePrettyFirstAction') }}
+ {% if isWidget %}<br/>{% else %}-{% endif %} {{ visitInfo.getColumn('serverTimePrettyFirstAction') }}</strong>
+{% if visitInfo.getColumn('visitIp') is not empty %}
+<span class="visitor-log-ip-location visitorLogTooltip" title="{% if visitInfo.getColumn('userId') is not empty %}{{ 'General_UserId'|translate }}: {{ visitInfo.getColumn('userId')|raw }}
+{% endif %}{% if visitInfo.getColumn('visitorId') is not empty %}{{ 'General_VisitorID'|translate }}: {{ visitInfo.getColumn('visitorId') }}
+{% endif %}{% if visitInfo.getColumn('idVisit') is not empty %}
+{{ 'General_Visit'|translate }} ID: {{ visitInfo.getColumn('idVisit') }}
+{% endif %}{% if visitInfo.getColumn('latitude') or visitInfo.getColumn('longitude') %}{{ visitInfo.getColumn('location') }}
+GPS (lat/long): {{ visitInfo.getColumn('latitude') }},{{ visitInfo.getColumn('longitude') }}{% endif %}">
+ IP: {{ visitInfo.getColumn('visitIp') }}
+ {% if visitInfo.getColumn('userId') is not empty %}<br/><br/>{{ visitInfo.getColumn('userId')|raw }}{% endif %}
+</span>{% endif %}
+{% if isWidget %}
+ <br />
+ {{ postEvent('Live.renderVisitorIcons', visitInfo) }}
+{% endif %}
diff --git a/plugins/Live/templates/_visitorLogIcons.twig b/plugins/Live/templates/_visitorLogIcons.twig
new file mode 100644
index 0000000000..63dbeb748a
--- /dev/null
+++ b/plugins/Live/templates/_visitorLogIcons.twig
@@ -0,0 +1,84 @@
+{% set visitHasEcommerceActivity = visitor.getColumn('visitEcommerceStatusIcon') %}
+{% set breakBeforeVisitorRank = (visitHasEcommerceActivity and visitor.getColumn('visitorTypeIcon')) ? true : false %}
+
+<span class="visitorLogIcons">
+
+ <span class="visitorDetails">
+ {% if visitor.getColumn('visitorTypeIcon') %}
+ <span class="visitorLogIconWithDetails visitorTypeIcon">
+ <img src="{{ visitor.getColumn('visitorTypeIcon') }}"/>
+ <ul class="details">
+ <li>{{ 'General_ReturningVisitor'|translate }} - {{ 'General_NVisits'|translate(visitor.getColumn('visitCount')) }}</li>
+ </ul>
+ </span>
+ {% endif %}
+ {% if visitor.getColumn('countryFlag') %}
+ <span class="visitorLogIconWithDetails flag" profile-header-text="{% if visitor.getColumn('city') %}{{ visitor.getColumn('city')|e('html_attr') }}{% else %}{{ visitor.getColumn('country') }}{% endif %}">
+
+ <img src="{{ visitor.getColumn('countryFlag') }}"/>
+ <ul class="details">
+ <li>{{ 'UserCountry_Country'|translate }}: {{ visitor.getColumn('country') }}</li>
+ {% if visitor.getColumn('region') %}<li>{{ 'UserCountry_Region'|translate }}: {{ visitor.getColumn('region') }}</li>{% endif %}
+ {% if visitor.getColumn('city') %}<li>{{ 'UserCountry_City'|translate }}: {{ visitor.getColumn('city') }}</li>{% endif %}
+ {% if visitor.getColumn('language') %}<li>{{ 'UserLanguage_BrowserLanguage'|translate }}: {{ visitor.getColumn('language') }}</li>{% endif %}
+ </ul>
+ </span>
+ {% endif %}
+ {% if visitor.getColumn('browserIcon') %}
+ <span class="visitorLogIconWithDetails" profile-header-text="{{ visitor.getColumn('browser')|e('html_attr') }}">
+ <img src="{{ visitor.getColumn('browserIcon') }}"/>
+ <ul class="details">
+ <li>{{ 'DevicesDetection_ColumnBrowser'|translate }}: {{ visitor.getColumn('browser') }}</li>
+ <li>{{ 'DevicesDetection_BrowserEngine'|translate }}: {{ visitor.getColumn('browserFamily') }}</li>
+ {% if visitor.getColumn('pluginsIcons')|length > 0 %}
+ <li>
+ {{ 'General_Plugins'|translate }}:
+ {% for pluginIcon in visitor.getColumn('pluginsIcons') %}
+ <img width="16px" height="16px" src="{{ pluginIcon.pluginIcon }}" alt="{{ pluginIcon.pluginName|capitalize(true) }}"/>
+ {% endfor %}
+ </li>
+ {% endif %}
+ </ul>
+ </span>
+ {% endif %}
+ {% if visitor.getColumn('operatingSystemIcon') %}
+ <span class="visitorLogIconWithDetails" profile-header-text="{{ visitor.getColumn('operatingSystem')|e('html_attr') }}">
+ <img src="{{ visitor.getColumn('operatingSystemIcon') }}"/>
+ <ul class="details">
+ <li>{{ 'DevicesDetection_ColumnOperatingSystem'|translate }}: {{ visitor.getColumn('operatingSystem') }}</li>
+ </ul>
+ </span>
+ {% endif %}
+ {% if visitor.getColumn('deviceTypeIcon') %}
+ <span class="visitorLogIconWithDetails" profile-header-text="{% if visitor.getColumn('resolution') %}{{ visitor.getColumn('resolution')|e('html_attr') }}{% else %}{{ visitor.getColumn('deviceType') }}{% endif %}">
+ <img src="{{ visitor.getColumn('deviceTypeIcon') }}"/>
+ <ul class="details">
+ <li>{{ 'DevicesDetection_DeviceType'|translate }}: {{ visitor.getColumn('deviceType') }}</li>
+ {% if visitor.getColumn('deviceBrand') %}<li>{{ 'DevicesDetection_DeviceBrand'|translate }}: {{ visitor.getColumn('deviceBrand') }}</li>{% endif %}
+ {% if visitor.getColumn('deviceModel') %}<li>{{ 'DevicesDetection_DeviceModel'|translate }}: {{ visitor.getColumn('deviceModel') }}</li>{% endif %}
+ {% if visitor.getColumn('resolution') %}<li>{{ 'Resolution_ColumnResolution'|translate }}: {{ visitor.getColumn('resolution') }}</li>{% endif %}
+ </ul>
+ </span>
+ {% endif %}
+ </span>
+
+ {% if visitor.getColumn('goalConversions') or visitHasEcommerceActivity %}
+ <span class="visitorType">
+ {# Goals, and/or Ecommerce activity #}
+ {% if visitor.getColumn('goalConversions') %}
+ <span title="{{ 'General_VisitConvertedNGoals'|translate(visitor.getColumn('goalConversions')) }}" class='visitorRank visitorLogTooltip'
+ {% if isWidget or breakBeforeVisitorRank %}style="margin-left:0;"{% endif %}>
+ <img src="{{ visitor.getColumn('visitConvertedIcon') }}"/>
+ {{ visitor.getColumn('goalConversions') }}
+ {% if visitHasEcommerceActivity %}
+ &nbsp;
+ <img src="{{ visitor.getColumn('visitEcommerceStatusIcon') }}" class='visitorLogTooltip' title="{{ visitor.getColumn('visitEcommerceStatus') }}"/>
+ {% endif %}
+ </span>
+ {# Ecommerce activity only (no goal) #}
+ {% elseif visitHasEcommerceActivity %}
+ <img class="visitorLogTooltip" src="{{ visitor.getColumn('visitEcommerceStatusIcon') }}" title="{{ visitor.getColumn('visitEcommerceStatus') }}"/>
+ {% endif %}
+ </span>
+ {% endif %}
+</span>
diff --git a/plugins/Live/templates/getSingleVisitSummary.twig b/plugins/Live/templates/getSingleVisitSummary.twig
deleted file mode 100644
index c7af9a6c2c..0000000000
--- a/plugins/Live/templates/getSingleVisitSummary.twig
+++ /dev/null
@@ -1,68 +0,0 @@
-{% macro customVar(id, customVariable) %}
- {% set name='customVariableName' ~ id %}
- {% set value='customVariableValue' ~ id %}
- <li><span>{{ customVariable[name]|truncate(30) }}</span>{% if customVariable[value]|length > 0 %}<strong>{{ customVariable[value]|truncate(50) }}</strong>{% endif %}</li>
-{% endmacro %}
-{% import _self as macros %}
-{% if showLocation|default(false) %}
-<div class="visitor-profile-latest-visit-loc" title="{{ visitData.location }}">
- <img src="{{ visitData.countryFlag }}"/>&nbsp;<span>{% if visitData.city is not empty %}{{ visitData.city }}{% else %}{{ visitData.country }}{% endif %}</span>
-</div>
-{% endif %}
-<div class="visitor-profile-latest-visit-column">
- <ul>
- <li>
- <span>{{ 'General_IP'|translate }}</span><strong {% if visitData.providerName is defined and visitData.providerName is not empty %}title="{{ 'Provider_ColumnProvider'|translate }}: {{ visitData.providerName }}"{% endif %}>{{ visitData.visitIp }}</strong>
- </li>
- <li class="visitor-profile-id">
- <span>{{ 'General_Id'|translate|upper }}</span>
- {% if widgetizedLink is defined %}<a class="visitor-profile-widget-link" href="{{ widgetizedLink }}" target="_blank" title="{{ 'Widgetize_OpenInNewWindow'|translate }} - {{ 'Live_VisitorProfile'|translate }} {{ 'General_Id'|translate|upper }} {{ visitData.visitorId }}">{% endif %}
- <strong>{{ visitData.visitorId }}</strong>
- {% if widgetizedLink is defined %}</a>{% endif %}
- <a class="visitor-profile-export" href="{{ exportLink }}" target="_blank" title="{{ 'General_ExportThisReport'|translate }}">
- <span class="icon-export"></span>
- </a>
- </li>
- <li>
- {% if visitData.browserName is defined %}
- <div class="visitor-profile-browser" title="{% if visitData.plugins is not defined %}{{ visitData.browser }}{% elseif visitData.plugins %}{{ 'DevicePlugins_BrowserWithPluginsEnabled'|translate(visitData.browser, visitData.plugins) }}{% else %}{{ 'DevicePlugins_BrowserWithNoPluginsEnabled'|translate(visitData.browser) }}{% endif %}">
- {% if visitData.browserIcon is defined %}<img src="{{ visitData.browserIcon }}" width="16px" height="16px"/>{% endif %}<span>{{ visitData.browserName|split(' ')[0] }}</span>
- </div>
- {% endif %}
-
- <div class="visitor-profile-os">
- {% if visitData.operatingSystemIcon is defined %}<img src="{{ visitData.operatingSystemIcon }}" width="16px" height="16px"/>{% endif %}{% if visitData.operatingSystem is defined %}<span>{{ visitData.operatingSystem }}</span>{% endif %}
- </div>
- </li>
- {% if visitData.resolution is defined %}<li><span>{{ 'Resolution_ColumnResolution'|translate }}</span><strong>{{ visitData.resolution }}</strong></li>{% endif %}
- {% if visitData.userId is not empty %}<li><span>{{ 'General_UserId'|translate }}</span><strong>{{ visitData.userId|raw }}</strong></li>{% endif %}
- {% if visitReferralSummary is defined %}
- {%- set keywordNotDefined = 'General_NotDefined'|translate('General_ColumnKeyword'|translate) -%}
- <li>
- <span>{{ 'General_DateRangeFrom'|translate }}</span>
- <strong {% if visitData.referrerType == 'search' and '(' not in visitReferralSummary %}title="{{ keywordNotDefined }}"{% endif %}>{{ visitReferralSummary }}</strong>
- </li>
- {% endif %}
- </ul>
-</div>
-<div class="visitor-profile-latest-visit-column">
- {% if visitData.customVariables is defined %}
- <ul>
- {% for id,customVariable in visitData.customVariables %}
- {% if loop.index0 < 4 %}
- {{ macros.customVar(id, customVariable) }}
- {% endif %}
- {% endfor %}
- </ul>
- {% endif %}
- {% if visitData.customVariables is defined and visitData.customVariables|length > 4 %}
- <ul class="visitor-profile-extra-cvars" style="display:none;">
- {% for id,customVariable in visitData.customVariables %}
- {% if loop.index0 >= 4 %}
- {{ macros.customVar(id, customVariable) }}
- {% endif %}
- {% endfor %}
- </ul>
- <p class="visitor-profile-see-more-cvars"><a href="#">&#x25bc;</a></p>
- {% endif %}
-</div>
diff --git a/plugins/Live/templates/getVisitList.twig b/plugins/Live/templates/getVisitList.twig
index 9266afbcb6..b64ed585c5 100644
--- a/plugins/Live/templates/getVisitList.twig
+++ b/plugins/Live/templates/getVisitList.twig
@@ -1,27 +1,35 @@
{% for visitInfo in visits.getRows() %}
-<li>
+<li data-number="{{ startCounter }}">
<div>
- <div class="visitor-profile-visit-title-row">
- <h2 class="visitor-profile-visit-title" data-idvisit="{{ visitInfo.getColumn('idVisit') }}" title="{{ 'Live_ClickToViewMoreAboutVisit'|translate }}">
- {{ 'General_Visit'|translate }} #{{ startCounter }}
+ <div class="visitor-profile-visit-title" data-idvisit="{{ visitInfo.getColumn('idVisit') }}" title="{{ 'Live_ClickToViewMoreAboutVisit'|translate }}">
+ {{ 'General_Visit'|translate }} #{{ startCounter }}
+ <span class="visitor-profile-date" title="{{ visitInfo.getColumn('serverDatePrettyFirstAction') }} {{ visitInfo.getColumn('serverTimePrettyFirstAction') }}">
+ {{ visitInfo.getColumn('serverDatePrettyFirstAction') }} {{ visitInfo.getColumn('serverTimePrettyFirstAction') }}
+ </span>
+ </div>
+ <div class="visitor-profile-visit-details-extended">
+ {{ postEvent('Live.renderVisitorDetails', visitInfo) }}
+ </div>
+ <div class="visitor-profile-visit-details">
+ {{ postEvent('Live.renderVisitorIcons', visitInfo) }}
+ <a href="#" class="visitor-profile-show-actions">
+ {% set actionCount = visitInfo.getColumn('actionDetails')|length %}
+ {% if visitInfo.truncatedActionsCount is defined %}
+ {% set actionCount = actionCount + visitInfo.truncatedActionsCount %}
+ {% endif %}
{% if visitInfo.getColumn('visitDuration') != 0 %}
- <span>&nbsp; ({{ visitInfo.getColumn('visitDurationPretty')|raw }})</span>
+ {{ 'Live_ActionsAndDuration'|translate(actionCount, visitInfo.getColumn('visitDurationPretty')) }}
+ {% else %}
+ {{ actionCount }} {{ 'General_Actions'|translate }}
{% endif %}
- <span class="visitor-profile-date" title="{{ visitInfo.getColumn('serverDatePrettyFirstAction') }} {{ visitInfo.getColumn('serverTimePrettyFirstAction') }}">
- {{ visitInfo.getColumn('serverDatePrettyFirstAction') }} {{ visitInfo.getColumn('serverTimePrettyFirstAction') }}
- </span>
- </h2>
+ </a>
</div>
- <ol class="visitor-profile-actions">
+ <ol class="visitorLog visitor-profile-actions">
{% include "@Live/_actionsList.twig" with {'actionDetails': visitInfo.getColumn('actionDetails'),
- 'clientSideParameters': {
- 'idSite': idSite,
- 'pageUrlNotDefined': 'General_NotDefined'|translate('Actions_ColumnPageURL'|translate)
- },
- 'overrideLinkStyle': false} %}
+ 'visitInfo': visitInfo} %}
</ol>
</div>
</li>
-{% set startCounter = startCounter + 1 %}
-{% endfor %}
+{% set startCounter = startCounter - 1 %}
+{% endfor %} \ No newline at end of file
diff --git a/plugins/Live/templates/getVisitorProfilePopup.twig b/plugins/Live/templates/getVisitorProfilePopup.twig
index a5b69e7fbd..f21a2477a3 100644
--- a/plugins/Live/templates/getVisitorProfilePopup.twig
+++ b/plugins/Live/templates/getVisitorProfilePopup.twig
@@ -1,174 +1,88 @@
{% if not visitorData %}
<div class="pk-emptyDataTable">{{ 'CoreHome_ThereIsNoDataForThisReport'|translate }}</div>
{% else %}
-<div class="visitor-profile"
- data-visitor-id="{{ visitorData.lastVisits.getFirstRow().getColumn('visitorId') }}"
- data-next-visitor="{{ visitorData.nextVisitorId }}"
- data-prev-visitor="{{ visitorData.previousVisitorId }}"
- tabindex="0">
- <a href class="visitor-profile-close" title="{{ 'General_Close'|translate }} "></a>
- <div class="visitor-profile-info">
- <div>
+ <div class="visitor-profile"
+ data-visitor-id="{{ visitorData.lastVisits.getFirstRow().getColumn('visitorId') }}"
+ data-next-visitor="{{ visitorData.nextVisitorId }}"
+ data-prev-visitor="{{ visitorData.previousVisitorId }}"
+ tabindex="0">
+ <div class="visitor-profile-options">
+ <a href class="visitor-profile-close" title="{{ 'General_Close'|translate }} "></a>
+ <a href="http://piwik.org/docs/user-profile/" class="visitor-profile-help" rel="noreferrer"
+ target="_blank"
+ title="{{ 'General_ViewDocumentationFor'|translate("Live_VisitorProfile"|translate|ucwords) }}">
+ </a>
+ <a href class="visitor-profile-toggle-actions" title="{{ 'Live_ToggleActions'|translate }} "></a>
+ </div>
+ <div class="visitor-profile-info">
<div class="visitor-profile-overview">
- <div class="visitor-profile-avatar">
- <div>
- <div class="visitor-profile-image-frame">
- <img src="{{ visitorData.visitorAvatar|default("plugins/Live/images/unknown_avatar.png") }}"
- alt="{{ visitorData.visitorDescription|default('') }}"
- title="{{ visitorData.visitorDescription|default('') }}" />
- </div>
- <img src="plugins/Live/images/paperclip.png" alt=""/>
+ <div class="visitor-profile-header">
+ <div class="visitor-profile-avatar">
+ <img src="{{ visitorData.visitorAvatar|default("plugins/Live/images/unknown_avatar.png") }}"
+ alt="{{ visitorData.visitorDescription|default('') }}"
+ title="{{ visitorData.visitorDescription|default('') }}"/>
</div>
- <div>
- <div class="visitor-profile-header">
- {% if visitorData.previousVisitorId is not empty %}<a class="visitor-profile-prev-visitor" href="#" title="{{ 'Live_PreviousVisitor'|translate }}">&larr;</a>{% endif %}
- <h1>{{ 'Live_VisitorProfile'|translate }}
- {%- if visitorData.userId is not empty %}: <span title="{{'General_UserId'|translate}}: {{ visitorData.userId|raw }}">{{ visitorData.userId|raw }}</span>{% endif -%}
- <img class="loadingPiwik" style="display:none;" src="plugins/Morpheus/images/loading-blue.gif"/>
+ <div class="visitor-profile-header-details">
+ <div class="visitor-profile-headline">
+ {% if visitorData.previousVisitorId is not empty %}<a class="visitor-profile-prev-visitor"
+ href="#"
+ title="{{ 'Live_PreviousVisitor'|translate }}">
+ &larr;</a>{% endif %}
+ <h1>
+ {%- if visitorData.userId is empty %}
+ {{ 'Live_VisitorProfile'|translate }}
+ {%- else %}
+ <span title="{{ 'General_UserId'|translate }}: {{ visitorData.userId|raw }}">{{ visitorData.userId|raw }}</span>
+ {% endif -%}
</h1>
- <a href="http://piwik.org/docs/user-profile/" class="visitorProfileHelp" rel="noreferrer" target="_blank" title="{{ 'General_ViewDocumentationFor'|translate("Live_VisitorProfile"|translate|ucwords) }}">
- <span class="icon-help"></span>
- </a>
- {% if visitorData.nextVisitorId is not empty %}<a class="visitor-profile-next-visitor" href="#" title="{{ 'Live_NextVisitor'|translate }}">&rarr;</a>{% endif %}
+ {% if visitorData.nextVisitorId is not empty %}<a class="visitor-profile-next-visitor"
+ href="#"
+ title="{{ 'Live_NextVisitor'|translate }}">
+ &rarr;</a>{% endif %}
</div>
<div class="visitor-profile-latest-visit">
- {% include "@Live/getSingleVisitSummary.twig" with {'visitData': visitorData.lastVisits.getFirstRow().getColumns(), 'showLocation': false} %}
- </div>
- </div>
- <p style="clear:both; border:none!important;"></p>
- </div>
- <div class="visitor-profile-summary">
- <h1>{{ 'General_Summary'|translate }}</h1>
- <div>
- {% if visitorData.totalPageViews != visitorData.totalActions %}
- {% set actionDetails = [] %}
- {% if visitorData.totalPageViews > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalPageViews ~ ' ' ~ 'General_ColumnPageviews'|translate]) %}{% endif %}
- {% if visitorData.totalEvents > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalEvents ~ ' ' ~ 'Events_Events'|translate]) %}{% endif %}
- {% if visitorData.totalDownloads > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalDownloads ~ ' ' ~ 'General_Downloads'|translate]) %}{% endif %}
- {% if visitorData.totalOutlinks > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalOutlinks ~ ' ' ~ 'General_Outlinks'|translate]) %}{% endif %}
- {% if visitorData.totalSearches > 0 %}{% set actionDetails = actionDetails|merge([visitorData.totalSearches ~ ' ' ~ 'Actions_ColumnSearches'|translate]) %}{% endif %}
- <p>{{ 'Live_VisitSummaryWithActionDetails'|translate('<strong>' ~ visitorData.totalVisitDurationPretty ~ '</strong>', '', '', '<strong>' ~ visitorData.totalActions, '</strong>', actionDetails|join(', ') , '<strong>' ~ visitorData.totalVisits, '</strong>')|raw }}</p>
- {% else %}
- <p>{{ 'Live_VisitSummary'|translate('<strong>' ~ visitorData.totalVisitDurationPretty ~ '</strong>', '', '', '<strong>' ~ visitorData.totalActions, '</strong>', '<strong>' ~ visitorData.totalVisits, '</strong>')|raw }}</p>
- {% endif %}
- <p>{% if visitorData.totalGoalConversions %}<strong>{% endif %}{{ 'Live_ConvertedNGoals'|translate(visitorData.totalGoalConversions) }}{% if visitorData.totalGoalConversions %}</strong>{% endif %}
- {%- if visitorData.totalGoalConversions %} (
- {%- for idGoal, totalConversions in visitorData.totalConversionsByGoal -%}
- {%- set idGoal = idGoal[7:] -%}
- {%- if not loop.first %}, {% endif -%}{{- totalConversions }} {{ goals[idGoal]['name'] -}}
- {%- endfor -%}
- ){% endif %}.</p>
- {% if visitorData.totalSearches|default(0) %}
- <p>
- {{ 'Actions_WidgetSearchKeywords'|translate }}:
- {%- for entry in visitorData.searches %} <strong title="{% if entry.searches == 1 %}{{ 'Actions_OneSearch'|translate }}{% else %}{{ 'UserCountryMap_Searches'|translate(entry.searches) }}{% endif %}">{{ entry.keyword }}</strong>{% if not loop.last %},{% endif %}{% endfor %}
- </p>
- {% endif %}
- {% if visitorData.averagePageGenerationTime is defined %}
- <p title="{{ 'Live_CalculatedOverNPageViews'|translate(visitorData.totalPageViewsWithTiming) }}">
- {{ 'Live_AveragePageGenerationTime'|translate('<strong>' ~ visitorData.averagePageGenerationTime ~ 's</strong>')|raw }}
- </p>
- {% endif %}
- </div>
- </div>
- {% if visitorData.totalEcommerceRevenue is defined %}
- <div class="visitor-profile-lifetimevalue">
- <h1>{{ 'Goals_Ecommerce'|translate }}</h1>
- <div>
- <p title="{{ 'Ecommerce_LifeTimeValueDescription'|translate(visitorData.visitorId) }}">
- {{ 'Ecommerce_VisitorProfileLTV'|translate( "<strong>" ~ visitorData.totalEcommerceRevenue|money(idSite) ~ "</strong>")|raw }}
- {{ 'Ecommerce_VisitorProfileItemsAndOrders'|translate("<strong>" ~ visitorData.totalEcommerceItems ~ "</strong>", "<strong>" ~ visitorData.totalEcommerceConversions ~ "</strong>")|raw }}
- </p>
- <p>
- {%- if visitorData.totalAbandonedCarts|default(0) > 0 %}
- {{ 'Ecommerce_VisitorProfileAbandonedCartSummary'|translate('<strong>' ~ visitorData.totalAbandonedCarts ~ '</strong>', '<strong>' ~ visitorData.totalAbandonedCartsItems ~ '</strong>', '<strong>' ~ visitorData.totalAbandonedCartsRevenue|money(idSite) ~ '</strong>')|raw }}
- {%- endif -%}
- </p>
- </div>
- </div>
- {% endif %}
- <div class="visitor-profile-important-visits">
- {%- set keywordNotDefined = 'General_NotDefined'|translate('General_ColumnKeyword'|translate) -%}
- <div>
- <h1>{% if visitorData.visitsAggregated == 100 %}{{ 'General_Visit'|translate }}# 100{% else %}{{ 'Live_FirstVisit'|translate }}{% endif %}</h1>
- <div>
- <p><strong>{{ visitorData.firstVisit.prettyDate }}</strong>&nbsp;- {{ 'UserCountryMap_DaysAgo'|translate(visitorData.firstVisit.daysAgo) }}</p>
- <p>
- {{ 'General_FromReferrer'|translate }}<strong {% if visitorData.firstVisit.referrerType == 'search' and '(' not in visitorData.firstVisit.referralSummary %}title="{{ keywordNotDefined }}"{% endif %}>{{ visitorData.firstVisit.referralSummary }}</strong></p>
+ <div class="visitor-profile-id">
+ <span>{{ 'General_Id'|translate|upper }}</span>
+ {% if widgetizedLink is defined %}<a class="visitor-profile-widget-link"
+ href="{{ widgetizedLink }}" target="_blank"
+ title="{{ 'Widgetize_OpenInNewWindow'|translate }} - {{ 'Live_VisitorProfile'|translate }} {{ 'General_Id'|translate|upper }} {{ visitorData.visitorId }}">{% endif %}
+ <span>{{ visitorData.visitorId }}</span>
+ {%- if widgetizedLink is defined %}</a>{% endif %}
+ <a class="visitor-profile-export" href="{{ exportLink }}" target="_blank"
+ title="{{ 'General_ExportThisReport'|translate }}">
+ <span class="icon-export"></span>
+ </a>
+ </div>
+ {{ postEvent('Live.renderVisitorIcons', visitorData.lastVisits|first) }}
</div>
</div>
- {% if visitorData.lastVisits.getRowsCount() != 1 %}
- <div>
- <h1>{{ 'Live_LastVisit'|translate }}</h1>
- <div>
- <p><strong>{{ visitorData.lastVisit.prettyDate }}</strong>&nbsp;- {{ 'UserCountryMap_DaysAgo'|translate(visitorData.lastVisit.daysAgo) }}</p>
- <p>
- {{ 'General_FromReferrer'|translate }}<strong {% if visitorData.lastVisit.referrerType == 'search' and '(' not in visitorData.lastVisit.referralSummary %}title="{{ keywordNotDefined }}"{% endif %}>{{ visitorData.lastVisit.referralSummary }}</strong></p>
- </div>
- </div>
- {% endif %}
</div>
- <div class="visitor-profile-location">
- <h1>{{ 'UserCountry_Location'|translate }}</h1>
- <p>
- {%- for entry in visitorData.countries -%}
-
- {% set entryCity -%}
- {% if entry.cities is defined and 1 == entry.cities|length and entry.cities|join -%}
- {{ entry.cities|join }}
- {%- elseif entry.cities is defined and 1 < entry.cities|length -%}
- <span title="{{ entry.cities|join(', ') }}">{{ 'UserCountry_FromDifferentCities'|translate }}</span>
- {%- endif %}
- {%- endset %}
-
- {% set entryVisits -%}
- <strong>
- {% if entry.nb_visits == 1 -%}
- {{ 'General_OneVisit'|translate }}
- {%- else -%}
- {{ 'General_NVisits'|translate(entry.nb_visits) }}
- {%- endif -%}
- </strong>
- {%- endset %}
- {% set entryCountry -%}
- {%- if entryCity -%}
- {{ 'UserCountry_CityAndCountry'|translate(entryCity, entry.prettyName)|raw }}
- {%- else -%}
- {{ entry.prettyName }}
- {%- endif -%}
-
- &nbsp;<img height="16px" src="{{ entry.flag }}" title="{{ entry.prettyName }}"/>
- {%- endset %}
-
- {{- 'General_XFromY'|translate(entryVisits, entryCountry)|raw -}}{% if not loop.last %}, {% endif %}
- {%- endfor %}
- <a class="visitor-profile-show-map" href="#" {% if userCountryMapUrl|default('') is empty %}style="display:none"{% endif %}>({{ 'Live_ShowMap'|translate|replace({' ': '&nbsp;'})|raw }})</a> <img class="loadingPiwik" style="display:none;" src="plugins/Morpheus/images/loading-blue.gif"/>
- </p>
- <div class="visitor-profile-map" style="display:none" data-href="{{ userCountryMapUrl|default('') }}">
- </div>
- </div>
+ {{ profileSummary|raw }}
{{ postEvent('Template.afterVisitorProfileOverview') }}
</div>
<div class="visitor-profile-visits-info">
<div class="visitor-profile-visits-container">
<ol class="visitor-profile-visits">
- {% include "@Live/getVisitList.twig" with {'visits': visitorData.lastVisits, 'startCounter': 1} %}
+ {% include "@Live/getVisitList.twig" with {'visits': visitorData.lastVisits, 'startCounter': visitorData.totalVisits} %}
</ol>
</div>
<div class="visitor-profile-more-info">
{% if visitorData.lastVisits.getRowsCount() >= constant("Piwik\\Plugins\\Live\\VisitorProfile::VISITOR_PROFILE_MAX_VISITS_TO_SHOW") %}
- <a href="#">{{ 'Live_LoadMoreVisits'|translate }}</a> <img class="loadingPiwik" style="display:none;" src="plugins/Morpheus/images/loading-blue.gif"/>
+ <a href="#">{{ 'Live_LoadMoreVisits'|translate }}</a> <img class="loadingPiwik"
+ style="display:none;"
+ src="plugins/Morpheus/images/loading-blue.gif"/>
{% else %}
- <span class="visitor-profile-no-visits">{{ 'Live_NoMoreVisits'|translate }}</span>
+ <span class="visitor-profile-no-visits">{{ 'Live_NoMoreVisits'|translate }}</span>
{% endif %}
</div>
</div>
</div>
</div>
-</div>
-<script type="text/javascript">
-$(function() { require('piwik/UI').VisitorProfileControl.initElements(); });
-</script>
+ <script type="text/javascript">
+ $(function () {
+ require('piwik/UI').VisitorProfileControl.initElements();
+ });
+ </script>
{% endif %} \ No newline at end of file
diff --git a/plugins/Live/tests/Fixtures/VisitsWithAllActionsAndDevices.php b/plugins/Live/tests/Fixtures/VisitsWithAllActionsAndDevices.php
new file mode 100644
index 0000000000..9938f4c25c
--- /dev/null
+++ b/plugins/Live/tests/Fixtures/VisitsWithAllActionsAndDevices.php
@@ -0,0 +1,221 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Plugins\Live\tests\Fixtures;
+
+use Piwik\Date;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Plugins\Goals\API as GoalsApi;
+use Piwik\Plugins\CustomDimensions\API as CustomDimensionsApi;
+
+/**
+ * Generates many visits for the same visitor
+ */
+class VisitsWithAllActionsAndDevices extends Fixture
+{
+ public $dateTime = '2010-02-01 11:22:33';
+ public $idSite = 1;
+
+ public function setUp()
+ {
+ if (!self::siteCreated($idSite = 1)) {
+ self::createWebsite($this->dateTime, 1);
+ }
+
+ GoalsApi::getInstance()->addGoal(1, 'Successfully used Search', 'manually', '', 'contains');
+
+ CustomDimensionsApi::getInstance()->configureNewCustomDimension(1, 'age', 'visit', 1);
+ CustomDimensionsApi::getInstance()->configureNewCustomDimension(1, 'currency', 'action', 1);
+
+ $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true);
+ $t->setTokenAuth(self::getTokenAuth());
+
+ $t->setUserId('X4F66G776HGI');
+
+ // smart display
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(0)->getDatetime(), 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; VSD220 Build/IMM76D.UI23ED12_VSC) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30');
+
+ // media player
+ $this->trackVisitMediaPlayer($t, Date::factory($this->dateTime)->addHour(6.33)->getDatetime());
+
+ // tv
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(16.6)->getDatetime(), 'Mozilla/5.0 (Linux; Android 4.2.2; AFTB Build/JDQ39) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.173 Mobile Safari/537.22 cordova-amazon-fireos/3.4.0 AmazonWebAppPlatform/3.4.0;2.0');
+
+ // desktop
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(26.7)->getDatetime(), 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; NP06; rv:11.0) like Gecko');
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(32.5)->getDatetime(), 'Safari/9537.73.11 CFNetwork/673.0.3 Darwin/13.0.0 (x86_64) (MacBookAir6%2C2)');
+
+ // car browser
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(60.4)->getDatetime(), 'Mozilla/5.0 (X11; u; Linux; C) AppleWebKit /533.3 (Khtml, like Gheko) QtCarBrowser Safari/533.3');
+
+ // unknown device
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(75.1)->getDatetime(), 'Mozilla/5.0 (Android; Linux armv7l; rv:10.0) Gecko/20120118 Firefox/10.0 Fennec/10.0');
+
+ // smartphone
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(79.5)->getDatetime(), 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; ADR910L 4G Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30');
+ $this->trackDeviceVisit($t, Date::factory($this->dateTime)->addHour(86.8)->getDatetime(), 'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-cn; ZTE N799D Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30; 360browser(securitypay,securityinstalled); 360(android,uppayplugin); 360 Aphone Browser (5.4.0)');
+
+ $this->trackVisitSmartphone($t, Date::factory($this->dateTime)->addHour(101.6)->getDatetime());
+ $this->trackVisitTablet($t, Date::factory($this->dateTime)->addHour(156.9)->getDatetime());
+ }
+
+ public function tearDown()
+ {
+ // empty
+ }
+
+ private function trackVisitSmartphone(\PiwikTracker $t, $dateTime)
+ {
+ $t->setForceVisitDateTime($dateTime);
+ $t->setUserAgent('Mozilla/5.0 (Linux; U; Android 4.4.2; fr-fr; HTC One_M8 Build/KOT49H) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16');
+
+ $t->setCountry('jp');
+ $t->setRegion("40");
+ $t->setCity('Tokyo');
+ $t->setLatitude(35.70);
+ $t->setLongitude(139.71);
+
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(251);
+ $t->setDebugStringAppend('bw_bytes=12053');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->doTrackContentImpression('product slider', 'product_16.jpg', 'http://example.org/product16');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.05)->getDatetime());
+ $t->doTrackEvent('product slider', 'next');
+ $t->doTrackContentImpression('product slider', 'product_42.jpg', 'http://example.org/product42');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.08)->getDatetime());
+ $t->doTrackContentInteraction('click', 'product slider', 'product_42.jpg', 'http://example.org/product42');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.1)->getDatetime());
+ $t->setUrl('http://example.org/product42');
+ $t->setCustomTrackingParameter('dimension2', 'NZD');
+ $t->setEcommerceView($sku = 'P42X4D', $name = 'product 42', $category = 'software', $price = 60);
+ $t->setGenerationTime(83);
+ $t->setDebugStringAppend('bw_bytes=36053');
+ self::checkResponse($t->doTrackPageView('product 42'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.14)->getDatetime());
+ $t->doTrackAction('http://example.org/product42/productsheet.pdf', 'download');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.2)->getDatetime());
+ $t->setUrl('http://example.org/product42');
+ $t->addEcommerceItem('P42X4D', 'product 42', 'software', $price = 60, $qty = 2);
+ self::checkResponse($t->doTrackEcommerceOrder('X42FCY', 140, 120, 20, 6.9, 6.9));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.25)->getDatetime());
+ $t->setUrl('http://example.org/search');
+ $t->setGenerationTime(318);
+ $t->setDebugStringAppend('bw_bytes=2583');
+ self::checkResponse($t->doTrackPageView('product search'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.29)->getDatetime());
+ $t->doTrackSiteSearch('fancy product', '', 12560);
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.32)->getDatetime());
+ $t->doTrackEvent('search', 'filter', 'enormous category');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.35)->getDatetime());
+ $t->doTrackSiteSearch('fancy product', 'enormous category', 13);
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.38)->getDatetime());
+ $t->doTrackGoal(1);
+
+ $t->setUrl('http://example.org/fancyproduct');
+ $t->setEcommerceView($sku = 'F4NCYX', $name = 'fancy product', $category = 'software', $price = 40);
+ $t->setGenerationTime(151);
+ $t->setDebugStringAppend('bw_bytes=68895');
+ self::checkResponse($t->doTrackPageView('fancy product'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.4)->getDatetime());
+ $t->addEcommerceItem('F4NCYX', 'fancy product', 'software', $price = 40, $qty = 2);
+ self::checkResponse($t->doTrackEcommerceCartUpdate(140));
+
+ $t->setUrl('http://example.org/cart');
+ $t->setGenerationTime(33);
+ $t->setDebugStringAppend('bw_bytes=1590');
+ self::checkResponse($t->doTrackPageView('cart'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.5)->getDatetime());
+ self::checkResponse($t->doTrackAction('http://vendor.site', 'link'));
+ }
+
+ private function trackVisitTablet(\PiwikTracker $t, $dateTime)
+ {
+ $t->setForceVisitDateTime($dateTime);
+ $t->setUserAgent('Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.8 Safari/535.19 Silk-Accelerated=true');
+
+ $t->setUrlReferrer('http://www.google.com/search?q=product%2042');
+ $t->setUrl('http://example.org/product42');
+ $t->setGenerationTime(96);
+ $t->setDebugStringAppend('bw_bytes=6851');
+ $t->setCustomVariable(1, 'custom', 'variable', 'page');
+ $t->setCustomTrackingParameter('dimension1', '42');
+ $t->setCustomTrackingParameter('dimension2', '€');
+ self::checkResponse($t->doTrackPageView('product 42'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.09)->getDatetime());
+ $t->setUrl('http://example.org/cart');
+ $t->addEcommerceItem('P42X4D', 'product 42', 'software', $price = 60, $qty = 1);
+ self::checkResponse($t->doTrackEcommerceOrder('R52Z6P', 66, 60, 6, 0, 0));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.2)->getDatetime());
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(511);
+ $t->setDebugStringAppend('bw_bytes=2012');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.2)->getDatetime());
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(511);
+ $t->setDebugStringAppend('bw_bytes=2012');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.2)->getDatetime());
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(222);
+ $t->setDebugStringAppend('bw_bytes=950');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->doTrackContentImpression('product slider', 'product_16.jpg', 'http://example.org/product16');
+ }
+
+ private function trackVisitMediaPlayer(\PiwikTracker $t, $dateTime)
+ {
+ $t->setForceVisitDateTime($dateTime);
+ $t->setUserAgent('Mozilla/5.0 (iPod; U; CPU iPhone OS 4_2_1 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148');
+
+ $t->setUrlReferrer('http://www.nice.website/page3');
+ $t->setCustomVariable(1, 'promo', 'summer', 'visit');
+ $t->setCustomTrackingParameter('dimension1', '16');
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(195);
+ $t->setDebugStringAppend('bw_bytes=631');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->doTrackContentImpression('product slider', 'product_16.jpg', 'http://example.org/product16');
+
+ $t->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.4)->getDatetime());
+ $t->addEcommerceItem('F4NCYX', 'fancy product', 'software', $price = 40, $qty = 3);
+ self::checkResponse($t->doTrackEcommerceCartUpdate(120));
+ }
+
+ private function trackDeviceVisit(\PiwikTracker $t, $dateTime, $useragent)
+ {
+ $t->setForceVisitDateTime($dateTime);
+ $t->setUserAgent($useragent);
+
+ $t->setUrl('http://example.org/');
+ $t->setGenerationTime(111);
+ $t->setDebugStringAppend('bw_bytes=555');
+ self::checkResponse($t->doTrackPageView('home'));
+
+ $t->doTrackContentImpression('product slider', 'product_16.jpg', 'http://example.org/product16');
+ }
+} \ No newline at end of file
diff --git a/plugins/Live/tests/System/expected/test___Live.getVisitorProfile.xml b/plugins/Live/tests/System/expected/test___Live.getVisitorProfile.xml
index 75a12099fb..94b05f931a 100644
--- a/plugins/Live/tests/System/expected/test___Live.getVisitorProfile.xml
+++ b/plugins/Live/tests/System/expected/test___Live.getVisitorProfile.xml
@@ -1,62 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
+
<totalVisits>31</totalVisits>
<totalVisitDuration>0</totalVisitDuration>
<totalActions>31</totalActions>
- <totalEvents>0</totalEvents>
<totalOutlinks>0</totalOutlinks>
<totalDownloads>0</totalDownloads>
<totalSearches>0</totalSearches>
<totalPageViews>31</totalPageViews>
+ <totalUniquePageViews>4</totalUniquePageViews>
+ <totalRevisitedPages>4</totalRevisitedPages>
<totalPageViewsWithTiming>0</totalPageViewsWithTiming>
+ <searches>
+ </searches>
<totalGoalConversions>0</totalGoalConversions>
<totalConversionsByGoal>
</totalConversionsByGoal>
+ <totalEvents>0</totalEvents>
<hasLatLong>0</hasLatLong>
- <searches>
- </searches>
- <continents>
- <row>
- <continent>eur</continent>
- <nb_visits>1</nb_visits>
- <prettyName>Europe</prettyName>
- </row>
- <row>
- <continent>unk</continent>
- <nb_visits>30</nb_visits>
- <prettyName>Unknown</prettyName>
- </row>
- </continents>
- <countries>
- <row>
- <country>fr</country>
- <nb_visits>1</nb_visits>
- <flag>plugins/Morpheus/icons/dist/flags/fr.png</flag>
- <prettyName>France</prettyName>
- </row>
- <row>
- <country>xx</country>
- <nb_visits>30</nb_visits>
- <flag>plugins/Morpheus/icons/dist/flags/xx.png</flag>
- <prettyName>Unknown</prettyName>
- </row>
- </countries>
- <totalVisitDurationPretty>0s</totalVisitDurationPretty>
- <firstVisit>
-
-
-
- <referrerType>direct</referrerType>
- <referralSummary>Direct Entry</referralSummary>
- </firstVisit>
- <lastVisit>
-
-
-
- <referrerType>direct</referrerType>
- <referralSummary>Direct Entry</referralSummary>
- </lastVisit>
- <visitsAggregated>31</visitsAggregated>
<lastVisits>
<row>
<idSite>1</idSite>
@@ -70,10 +31,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>31</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -83,13 +47,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -125,6 +94,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -158,17 +133,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -182,10 +146,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>30</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -195,13 +162,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -237,6 +209,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -270,17 +248,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -294,10 +261,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>29</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -307,13 +277,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -349,6 +324,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -382,17 +363,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -406,10 +376,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>28</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -419,13 +392,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -461,6 +439,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -494,17 +478,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -518,10 +491,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>27</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -531,13 +507,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -573,6 +554,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -606,17 +593,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -630,10 +606,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>26</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -643,13 +622,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -685,6 +669,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -718,17 +708,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -742,10 +721,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>25</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -755,13 +737,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -797,6 +784,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -830,17 +823,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -854,10 +836,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>24</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -867,13 +852,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -909,6 +899,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -942,17 +938,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -966,10 +951,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>23</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -979,13 +967,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1021,6 +1014,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1054,17 +1053,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1078,10 +1066,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>22</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1091,13 +1082,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1133,6 +1129,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1166,21 +1168,81 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</lastVisits>
- <userId>0</userId>
-
+ <totalVisitDurationPretty>0s</totalVisitDurationPretty>
+ <userId>0</userId>
+ <firstVisit>
+
+
+
+ <referrerType>direct</referrerType>
+ <referrerUrl />
+ <referralSummary>Direct Entry</referralSummary>
+ </firstVisit>
+ <lastVisit>
+
+
+
+ <referrerType>direct</referrerType>
+ <referrerUrl />
+ <referralSummary>Direct Entry</referralSummary>
+ </lastVisit>
+ <visitsAggregated>10</visitsAggregated>
+ <visitedPages>
+ <row key="http://example.org/my/dir/page0">8</row>
+ <row key="http://example.org/my/dir/page1">8</row>
+ <row key="http://example.org/my/dir/page2">8</row>
+ <row key="http://example.org/my/dir/page3">7</row>
+ </visitedPages>
+ <devices>
+ <Unknown>
+ <count>30</count>
+ <icon>plugins/Morpheus/icons/dist/devices/unknown.png</icon>
+ <devices>
+ <row>
+ <name>Unknown</name>
+ <count>30</count>
+ </row>
+ </devices>
+ </Unknown>
+ <Desktop>
+ <count>1</count>
+ <icon>plugins/Morpheus/icons/dist/devices/desktop.png</icon>
+ <devices>
+ <row>
+ <name>Unknown</name>
+ <count>1</count>
+ </row>
+ </devices>
+ </Desktop>
+ </devices>
+ <continents>
+ <row>
+ <continent>eur</continent>
+ <nb_visits>1</nb_visits>
+ <prettyName>Europe</prettyName>
+ </row>
+ <row>
+ <continent>unk</continent>
+ <nb_visits>30</nb_visits>
+ <prettyName>Unknown</prettyName>
+ </row>
+ </continents>
+ <countries>
+ <row>
+ <country>fr</country>
+ <nb_visits>1</nb_visits>
+ <flag>plugins/Morpheus/icons/dist/flags/fr.png</flag>
+ <prettyName>France</prettyName>
+ </row>
+ <row>
+ <country>xx</country>
+ <nb_visits>30</nb_visits>
+ <flag>plugins/Morpheus/icons/dist/flags/xx.png</flag>
+ <prettyName>Unknown</prettyName>
+ </row>
+ </countries>
</result> \ No newline at end of file
diff --git a/plugins/Live/tests/System/expected/test_higherLimit__Live.getVisitorProfile.xml b/plugins/Live/tests/System/expected/test_higherLimit__Live.getVisitorProfile.xml
index 2a194415dc..481470e978 100644
--- a/plugins/Live/tests/System/expected/test_higherLimit__Live.getVisitorProfile.xml
+++ b/plugins/Live/tests/System/expected/test_higherLimit__Live.getVisitorProfile.xml
@@ -1,62 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
+
<totalVisits>31</totalVisits>
<totalVisitDuration>0</totalVisitDuration>
<totalActions>31</totalActions>
- <totalEvents>0</totalEvents>
<totalOutlinks>0</totalOutlinks>
<totalDownloads>0</totalDownloads>
<totalSearches>0</totalSearches>
<totalPageViews>31</totalPageViews>
+ <totalUniquePageViews>4</totalUniquePageViews>
+ <totalRevisitedPages>4</totalRevisitedPages>
<totalPageViewsWithTiming>0</totalPageViewsWithTiming>
+ <searches>
+ </searches>
<totalGoalConversions>0</totalGoalConversions>
<totalConversionsByGoal>
</totalConversionsByGoal>
+ <totalEvents>0</totalEvents>
<hasLatLong>0</hasLatLong>
- <searches>
- </searches>
- <continents>
- <row>
- <continent>eur</continent>
- <nb_visits>1</nb_visits>
- <prettyName>Europe</prettyName>
- </row>
- <row>
- <continent>unk</continent>
- <nb_visits>30</nb_visits>
- <prettyName>Unknown</prettyName>
- </row>
- </continents>
- <countries>
- <row>
- <country>fr</country>
- <nb_visits>1</nb_visits>
- <flag>plugins/Morpheus/icons/dist/flags/fr.png</flag>
- <prettyName>France</prettyName>
- </row>
- <row>
- <country>xx</country>
- <nb_visits>30</nb_visits>
- <flag>plugins/Morpheus/icons/dist/flags/xx.png</flag>
- <prettyName>Unknown</prettyName>
- </row>
- </countries>
- <totalVisitDurationPretty>0s</totalVisitDurationPretty>
- <firstVisit>
-
-
-
- <referrerType>direct</referrerType>
- <referralSummary>Direct Entry</referralSummary>
- </firstVisit>
- <lastVisit>
-
-
-
- <referrerType>direct</referrerType>
- <referralSummary>Direct Entry</referralSummary>
- </lastVisit>
- <visitsAggregated>31</visitsAggregated>
<lastVisits>
<row>
<idSite>1</idSite>
@@ -70,10 +31,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>31</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -83,13 +47,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -125,6 +94,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -158,17 +133,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -182,10 +146,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>30</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -195,13 +162,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -237,6 +209,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -270,17 +248,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -294,10 +261,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>29</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -307,13 +277,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -349,6 +324,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -382,17 +363,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -406,10 +376,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>28</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -419,13 +392,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -461,6 +439,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -494,17 +478,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -518,10 +491,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>27</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -531,13 +507,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -573,6 +554,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -606,17 +593,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -630,10 +606,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>26</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -643,13 +622,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -685,6 +669,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -718,17 +708,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -742,10 +721,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>25</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -755,13 +737,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -797,6 +784,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -830,17 +823,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -854,10 +836,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>24</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -867,13 +852,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -909,6 +899,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -942,17 +938,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -966,10 +951,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>23</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -979,13 +967,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1021,6 +1014,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1054,17 +1053,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1078,10 +1066,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>22</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1091,13 +1082,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1133,6 +1129,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1166,17 +1168,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1190,10 +1181,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>21</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1203,13 +1197,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1245,6 +1244,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1278,17 +1283,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1302,10 +1296,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>20</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1315,13 +1312,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1357,6 +1359,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1390,17 +1398,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1414,10 +1411,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>19</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1427,13 +1427,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1469,6 +1474,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1502,17 +1513,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1526,10 +1526,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>18</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1539,13 +1542,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1581,6 +1589,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1614,17 +1628,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1638,10 +1641,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>17</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1651,13 +1657,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1693,6 +1704,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1726,17 +1743,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1750,10 +1756,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>16</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1763,13 +1772,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1805,6 +1819,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1838,17 +1858,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1862,10 +1871,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>6</pageIdAction>
+
<pageId>15</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1875,13 +1887,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -1917,6 +1934,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -1950,17 +1973,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -1974,10 +1986,13 @@
<pageTitle>incredible title 1</pageTitle>
<pageIdAction>4</pageIdAction>
+
<pageId>14</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -1987,13 +2002,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -2029,6 +2049,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -2062,17 +2088,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -2086,10 +2101,13 @@
<pageTitle>incredible title 0</pageTitle>
<pageIdAction>2</pageIdAction>
+
<pageId>13</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -2099,13 +2117,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -2141,6 +2164,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -2174,17 +2203,6 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
<row>
<idSite>1</idSite>
@@ -2198,10 +2216,13 @@
<pageTitle>incredible title 2</pageTitle>
<pageIdAction>7</pageIdAction>
+
<pageId>12</pageId>
+ <bandwidth />
<interactionPosition>1</interactionPosition>
<icon />
+ <bandwidth_pretty>0 M</bandwidth_pretty>
</row>
</actionDetails>
<goalConversions>0</goalConversions>
@@ -2211,13 +2232,18 @@
+
+
+
+
+
+
<userId />
<visitorType>new</visitorType>
<visitorTypeIcon />
<visitConverted>0</visitConverted>
<visitConvertedIcon />
<visitCount>1</visitCount>
-
<visitEcommerceStatus>none</visitEcommerceStatus>
<visitEcommerceStatusIcon />
<daysSinceFirstVisit>0</daysSinceFirstVisit>
@@ -2253,6 +2279,12 @@
<browserIcon>plugins/Morpheus/icons/dist/browsers/UNK.png</browserIcon>
<browserCode>UNK</browserCode>
<browserVersion />
+ <totalEcommerceRevenue>0</totalEcommerceRevenue>
+ <totalEcommerceConversions>0</totalEcommerceConversions>
+ <totalEcommerceItems>0</totalEcommerceItems>
+ <totalAbandonedCartsRevenue>0</totalAbandonedCartsRevenue>
+ <totalAbandonedCarts>0</totalAbandonedCarts>
+ <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
<events>0</events>
<continent>Unknown</continent>
<continentCode>unk</continentCode>
@@ -2286,21 +2318,81 @@
<pluginName>java</pluginName>
</row>
</pluginsIcons>
-
-
-
-
-
- <totalEcommerceRevenue>0.00</totalEcommerceRevenue>
- <totalEcommerceConversions>0</totalEcommerceConversions>
- <totalEcommerceItems>0</totalEcommerceItems>
- <totalAbandonedCartsRevenue>0.00</totalAbandonedCartsRevenue>
- <totalAbandonedCarts>0</totalAbandonedCarts>
- <totalAbandonedCartsItems>0</totalAbandonedCartsItems>
</row>
</lastVisits>
- <userId>0</userId>
-
+ <totalVisitDurationPretty>0s</totalVisitDurationPretty>
+ <userId>0</userId>
+ <firstVisit>
+
+
+
+ <referrerType>direct</referrerType>
+ <referrerUrl />
+ <referralSummary>Direct Entry</referralSummary>
+ </firstVisit>
+ <lastVisit>
+
+
+
+ <referrerType>direct</referrerType>
+ <referrerUrl />
+ <referralSummary>Direct Entry</referralSummary>
+ </lastVisit>
+ <visitsAggregated>20</visitsAggregated>
+ <visitedPages>
+ <row key="http://example.org/my/dir/page0">8</row>
+ <row key="http://example.org/my/dir/page1">8</row>
+ <row key="http://example.org/my/dir/page2">8</row>
+ <row key="http://example.org/my/dir/page3">7</row>
+ </visitedPages>
+ <devices>
+ <Unknown>
+ <count>30</count>
+ <icon>plugins/Morpheus/icons/dist/devices/unknown.png</icon>
+ <devices>
+ <row>
+ <name>Unknown</name>
+ <count>30</count>
+ </row>
+ </devices>
+ </Unknown>
+ <Desktop>
+ <count>1</count>
+ <icon>plugins/Morpheus/icons/dist/devices/desktop.png</icon>
+ <devices>
+ <row>
+ <name>Unknown</name>
+ <count>1</count>
+ </row>
+ </devices>
+ </Desktop>
+ </devices>
+ <continents>
+ <row>
+ <continent>eur</continent>
+ <nb_visits>1</nb_visits>
+ <prettyName>Europe</prettyName>
+ </row>
+ <row>
+ <continent>unk</continent>
+ <nb_visits>30</nb_visits>
+ <prettyName>Unknown</prettyName>
+ </row>
+ </continents>
+ <countries>
+ <row>
+ <country>fr</country>
+ <nb_visits>1</nb_visits>
+ <flag>plugins/Morpheus/icons/dist/flags/fr.png</flag>
+ <prettyName>France</prettyName>
+ </row>
+ <row>
+ <country>xx</country>
+ <nb_visits>30</nb_visits>
+ <flag>plugins/Morpheus/icons/dist/flags/xx.png</flag>
+ <prettyName>Unknown</prettyName>
+ </row>
+ </countries>
</result> \ No newline at end of file
diff --git a/plugins/Live/tests/UI/Live_spec.js b/plugins/Live/tests/UI/Live_spec.js
new file mode 100644
index 0000000000..624ac5f468
--- /dev/null
+++ b/plugins/Live/tests/UI/Live_spec.js
@@ -0,0 +1,58 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * Screenshot integration tests.
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+describe("Live", function () {
+ this.timeout(0);
+
+ this.fixture = "Piwik\\Plugins\\Live\\tests\\Fixtures\\VisitsWithAllActionsAndDevices";
+
+ it('should show visitor log', function (done) {
+ expect.screenshot('visitor_log').to.be.captureSelector('.reporting-page', function (page) {
+ page.load("?module=CoreHome&action=index&idSite=1&period=year&date=2010-01-03#?idSite=1&period=year&date=2010-01-03&category=General_Visitors&subcategory=Live_VisitorLog");
+ page.wait(4000);
+ }, done);
+ });
+
+ it('should show visitor profile', function (done) {
+ expect.screenshot('visitor_profile').to.be.captureSelector('.ui-dialog', function (page) {
+ page.evaluate(function(){
+ $('.card:first-child .visitor-log-visitor-profile-link').click();
+ });
+ page.wait(6000);
+ }, done);
+ });
+
+ it('should hide all action details', function (done) {
+ expect.screenshot('visitor_profile_actions_hidden').to.be.captureSelector('.ui-dialog', function (page) {
+ page.evaluate(function(){
+ $('.visitor-profile-toggle-actions').click();
+ }, 500);
+ }, done);
+ });
+
+ it('should show visit details', function (done) {
+ expect.screenshot('visitor_profile_visit_details').to.be.captureSelector('.ui-dialog', function (page) {
+ page.evaluate(function(){
+ $('.visitor-profile-visit-title')[0].click();
+ }, 200);
+ }, done);
+ });
+
+ it('should show action details', function (done) {
+ expect.screenshot('visitor_profile_action_details').to.be.captureSelector('.ui-dialog', function (page) {
+ page.click('.visitor-profile-visits li:first-child .visitor-profile-show-actions', 200);
+ }, done);
+ });
+
+ it('should show action tooltip', function (done) {
+ expect.screenshot('visitor_profile_action_tooltip').to.be.captureSelector('.ui-tooltip:visible', function (page) {
+ page.mouseMove('.visitor-profile-visits li:first-child .visitor-profile-actions .action:first-child', 200);
+ }, done);
+ });
+}); \ No newline at end of file
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_log.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_log.png
new file mode 100644
index 0000000000..c4f62dc683
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_log.png
Binary files differ
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile.png
new file mode 100644
index 0000000000..f727dc862a
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile.png
Binary files differ
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_details.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_details.png
new file mode 100644
index 0000000000..4048ddfc59
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_details.png
Binary files differ
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_tooltip.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_tooltip.png
new file mode 100644
index 0000000000..3c59df6d85
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_action_tooltip.png
Binary files differ
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_actions_hidden.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_actions_hidden.png
new file mode 100644
index 0000000000..0838f7fd0a
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_actions_hidden.png
Binary files differ
diff --git a/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_visit_details.png b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_visit_details.png
new file mode 100644
index 0000000000..0358e64d08
--- /dev/null
+++ b/plugins/Live/tests/UI/expected-ui-screenshots/Live_visitor_profile_visit_details.png
Binary files differ
diff --git a/plugins/MarketingCampaignsReporting b/plugins/MarketingCampaignsReporting
-Subproject 1b523d822a5b2fc245412c751a0acc6a5875f2e
+Subproject 73b17d0b3ef57d96578a7782030ab5f04182072
diff --git a/plugins/Morpheus/icons b/plugins/Morpheus/icons
-Subproject 9d8522f98a2c9c5de4f7c267f0ca0618b185a87
+Subproject 0c4e30d95c1a36bf540df5e5d67a3161053c490
diff --git a/plugins/Morpheus/images/event.png b/plugins/Morpheus/images/event.png
index ad4b38a01b..bea57d4933 100644
--- a/plugins/Morpheus/images/event.png
+++ b/plugins/Morpheus/images/event.png
Binary files differ
diff --git a/plugins/Morpheus/stylesheets/general/_default.less b/plugins/Morpheus/stylesheets/general/_default.less
index 68d1827806..cfbd8ec0af 100644
--- a/plugins/Morpheus/stylesheets/general/_default.less
+++ b/plugins/Morpheus/stylesheets/general/_default.less
@@ -11,6 +11,7 @@ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockq
abbr {
border-bottom: 1px dotted;
+ text-decoration: none;
}
form {
diff --git a/plugins/Morpheus/stylesheets/main.less b/plugins/Morpheus/stylesheets/main.less
index db3515a1f6..1eaf784455 100644
--- a/plugins/Morpheus/stylesheets/main.less
+++ b/plugins/Morpheus/stylesheets/main.less
@@ -409,10 +409,6 @@ table.dataTable {
}
}
}
-
- &.dataTableVizVisitorLog {
-
- }
}
div.dataTableVizHtmlTable:not(.dataTableActions), div.dataTableVizAllColumns, div.dataTableVizGoals {
@@ -490,156 +486,6 @@ div.sparkline {
z-index: 1;
}
-.visitor-profile a {
- color: @theme-color-link;
- font-weight: normal;
-}
-
-.visitor-profile-info {
- box-shadow: none !important;
-}
-
-.visitor-profile-latest-visit-loc {
- display: inline-block;
- position: absolute;
- right: 4px;
- top: -19px;
-}
-
-
-.visitor-profile-more-info > a {
- color: @theme-color-link;
- .font-default(12px, 16px);
-}
-
-.visitor-profile-more-info {
- margin: 5px 0 15px 0;
-}
-
-.visitor-profile-visits-container {
- padding: 0;
- margin: 0;
- li {
- margin: 0 !important;
- background: @color-silver-l95;
- padding: 7px 10px !important;
- > div {
- border: 0px !important;
- margin: 0 !important;
- }
- }
-
- ol.visitor-profile-visits {
- > li {
- padding: 0 0 0 !important;
- span {
- font-weight: normal;
- margin-right: 20px;
- }
-
- ol {
- background: @theme-color-background-contrast !important;
- border-top: 0 !important;
- li {
- background: @theme-color-background-contrast !important;
- font-weight: normal;
- color: @theme-color-text-lighter;
- &:last-child {
- border-bottom: 0 !important;
- padding-bottom: 20px !important;
- }
- &:first-child {
- padding-top: 20px !important;
- }
- }
- }
- }
- }
-}
-
-.widget .visitor-profile .visitor-profile-info > div > div {
- min-width: 100% !important;
-}
-
-.visitor-profile {
- background: none;
- border: 0;
- .border-radius(0px);
- .visitor-profile-info {
- .border-radius(0px);
- border: 0px;
-
- > div {
- border: 0px !important;
- }
-
- .visitor-profile-image-frame {
- background: none !important;
- }
- .visitor-profile-avatar {
- > div > img {
- display: none;
- }
- }
- }
-
-
-
- .visitor-profile-avatar {
- ul {
- width: 100% !important;
- li {
- display: block;
- border: 0px;
- &:first-child {
- border: 0px !important;
- }
- span {
- color: @theme-color-text-lighter;
- .font-default(13px, 18px);
- padding-left: 0;
- }
-
- strong {
- color: @theme-color-text;
- .font-default(13px, 18px);
- font-weight: normal !important;
- }
-
- .visitor-profile-os,
- .visitor-profile-browser {
- margin-left: 0;
- img {
- margin-right: 5px;
- vertical-align: middle;
- }
- }
- }
- }
- }
-
- .visitor-profile-avatar > div:nth-child(2n) {
- width: 376px;
- }
-
- .visitor-profile-latest-visit {
- .visitor-profile-latest-visit-column {
- display: inline-block;
- margin-left: 0;
- }
-
- .visitor-profile-latest-visit-column:first-child {
- width: 50%;
- margin-right:-4px;
- }
-
- .visitor-profile-latest-visit-column:last-child {
- width: 50%;
- margin-right:-4px;
- }
- }
-}
-
.annotationView {
.font-default(10px, 12px);
text-transform: uppercase;
diff --git a/plugins/ProfessionalServices/templates/promoSessionRecordings.twig b/plugins/ProfessionalServices/templates/promoSessionRecordings.twig
index b43bb1af32..17e350f0fd 100644
--- a/plugins/ProfessionalServices/templates/promoSessionRecordings.twig
+++ b/plugins/ProfessionalServices/templates/promoSessionRecordings.twig
@@ -1,3 +1,3 @@
-<p style="margin-top:8px" class="alert-info alert">Did you know?
+<p class="alert-info alert">Did you know?
With <a target="_blank" rel="noreferrer" href="https://piwik.org/recommends/heatmap-session-recording-learn-more/">Heatmap & Session Recording</a> you can record all clicks, mouse movements, scrolls and form interactions of your visitors and replay them in a video to truly understand your visitors.
</p> \ No newline at end of file
diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php
index 4aed41100c..c275e09fc2 100644
--- a/plugins/Provider/Provider.php
+++ b/plugins/Provider/Provider.php
@@ -17,16 +17,6 @@ use Piwik\Piwik;
class Provider extends \Piwik\Plugin
{
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails'
- );
- }
-
public function install()
{
// add column hostname / hostname ext in the visit table
@@ -42,15 +32,6 @@ class Provider extends \Piwik\Plugin
}
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['provider'] = $instance->getProvider();
- $visitor['providerName'] = $instance->getProviderName();
- $visitor['providerUrl'] = $instance->getProviderUrl();
- }
-
public function uninstall()
{
// add column hostname / hostname ext in the visit table
diff --git a/plugins/Provider/Visitor.php b/plugins/Provider/Visitor.php
deleted file mode 100644
index c11f1e3a9b..0000000000
--- a/plugins/Provider/Visitor.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Provider;
-
-use Piwik\Piwik;
-
-require_once PIWIK_INCLUDE_PATH . '/plugins/Provider/functions.php';
-
-class Visitor
-{
- private $details = array();
-
- public function __construct($details)
- {
- $this->details = $details;
- }
-
- public function getProvider()
- {
- if (isset($this->details['location_provider'])) {
- return $this->details['location_provider'];
- }
- return Piwik::translate('General_Unknown');
- }
-
- public function getProviderName()
- {
- return getPrettyProviderName($this->getProvider());
- }
-
- public function getProviderUrl()
- {
- return getHostnameUrl(@$this->details['location_provider']);
- }
-} \ No newline at end of file
diff --git a/plugins/Provider/VisitorDetails.php b/plugins/Provider/VisitorDetails.php
new file mode 100644
index 0000000000..d0f8f146b7
--- /dev/null
+++ b/plugins/Provider/VisitorDetails.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Provider;
+
+use Piwik\Piwik;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\View;
+
+/**
+ * @see plugins/Provider/functions.php
+ */
+require_once PIWIK_INCLUDE_PATH . '/plugins/Provider/functions.php';
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['provider'] = $this->details['location_provider'];
+ $visitor['providerName'] = $this->getProviderName();
+ $visitor['providerUrl'] = $this->getProviderUrl();
+ }
+
+ public function renderVisitorDetails($visitorDetails)
+ {
+ if (empty($visitorDetails['provider'])) {
+ return [];
+ }
+
+ $view = new View('@Provider/_visitorDetails.twig');
+ $view->visitInfo = $visitorDetails;
+ return [[ 20, $view->render() ]];
+ }
+
+ protected function getProvider()
+ {
+ if (isset($this->details['location_provider'])) {
+ return $this->details['location_provider'];
+ }
+ return Piwik::translate('General_Unknown');
+ }
+
+ protected function getProviderName()
+ {
+ return getPrettyProviderName($this->getProvider());
+ }
+
+ protected function getProviderUrl()
+ {
+ return getHostnameUrl(@$this->details['location_provider']);
+ }
+} \ No newline at end of file
diff --git a/plugins/Provider/templates/_visitorDetails.twig b/plugins/Provider/templates/_visitorDetails.twig
new file mode 100644
index 0000000000..0cfdbe6b4b
--- /dev/null
+++ b/plugins/Provider/templates/_visitorDetails.twig
@@ -0,0 +1,9 @@
+<div class="visitorProvider">
+ <br />
+ {{ 'Provider_ColumnProvider'|translate }}:
+ {% if visitInfo.getColumn('providerUrl') %}
+ <a href="{{ visitInfo.getColumn('providerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitInfo.getColumn('providerName') }} {{ visitInfo.getColumn('providerUrl') }}" style="text-decoration:underline;">
+ {%- endif %}
+ {{ visitInfo.getColumn('providerName') }}
+ {%- if visitInfo.getColumn('providerUrl') %}</a>{% endif %}
+</div> \ No newline at end of file
diff --git a/plugins/Referrers/Referrers.php b/plugins/Referrers/Referrers.php
index 9d4d03a4a1..4e18abc933 100644
--- a/plugins/Referrers/Referrers.php
+++ b/plugins/Referrers/Referrers.php
@@ -30,7 +30,6 @@ class Referrers extends \Piwik\Plugin
{
return array(
'Insights.addReportToOverview' => 'addReportToInsightsOverview',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
'Request.getRenamedModuleAndAction' => 'renameDeprecatedModuleAndAction',
'Tracker.setTrackerCacheGeneral' => 'setTrackerCacheGeneral'
);
@@ -51,20 +50,6 @@ class Referrers extends \Piwik\Plugin
}
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['referrerType'] = $instance->getReferrerType();
- $visitor['referrerTypeName'] = $instance->getReferrerTypeName();
- $visitor['referrerName'] = $instance->getReferrerName();
- $visitor['referrerKeyword'] = $instance->getKeyword();
- $visitor['referrerKeywordPosition'] = $instance->getKeywordPosition();
- $visitor['referrerUrl'] = $instance->getReferrerUrl();
- $visitor['referrerSearchEngineUrl'] = $instance->getSearchEngineUrl();
- $visitor['referrerSearchEngineIcon'] = $instance->getSearchEngineIcon();
- }
-
public function addReportToInsightsOverview(&$reports)
{
$reports['Referrers_getWebsites'] = array();
diff --git a/plugins/Referrers/Visitor.php b/plugins/Referrers/VisitorDetails.php
index b10b9b953d..f0021c9293 100644
--- a/plugins/Referrers/Visitor.php
+++ b/plugins/Referrers/VisitorDetails.php
@@ -2,27 +2,38 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\Referrers;
-use Piwik\Url;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
use Piwik\UrlHelper;
+use Piwik\View;
-require_once PIWIK_INCLUDE_PATH . '/plugins/Referrers/functions.php';
-
-class Visitor
+class VisitorDetails extends VisitorDetailsAbstract
{
- private $details = array();
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['referrerType'] = $this->getReferrerType();
+ $visitor['referrerTypeName'] = $this->getReferrerTypeName();
+ $visitor['referrerName'] = $this->getReferrerName();
+ $visitor['referrerKeyword'] = $this->getKeyword();
+ $visitor['referrerKeywordPosition'] = $this->getKeywordPosition();
+ $visitor['referrerUrl'] = $this->getReferrerUrl();
+ $visitor['referrerSearchEngineUrl'] = $this->getSearchEngineUrl();
+ $visitor['referrerSearchEngineIcon'] = $this->getSearchEngineIcon();
+ }
- public function __construct($details)
+ public function renderVisitorDetails($visitorDetails)
{
- $this->details = $details;
+ $view = new View('@Referrers/_visitorDetails.twig');
+ $view->visitInfo = $visitorDetails;
+ return [[ 10, $view->render() ]];
}
- public function getReferrerType()
+ protected function getReferrerType()
{
try {
$referrerType = getReferrerTypeFromShortName($this->details['referer_type']);
@@ -33,15 +44,15 @@ class Visitor
return $referrerType;
}
- public function getReferrerTypeName()
+ protected function getReferrerTypeName()
{
return getReferrerTypeLabel($this->details['referer_type']);
}
- public function getKeyword()
+ protected function getKeyword()
{
$keyword = $this->details['referer_keyword'];
-
+
if ($this->getReferrerType() == 'search') {
$keyword = API::getCleanKeyword($keyword);
}
@@ -49,27 +60,8 @@ class Visitor
return urldecode($keyword);
}
- public function getReferrerUrl()
+ protected function getReferrerUrl()
{
- if ($this->getReferrerType() == 'search') {
- if ($this->details['referer_keyword'] == API::LABEL_KEYWORD_NOT_DEFINED) {
-
- return 'http://piwik.org/faq/general/#faq_144';
-
- } // Case URL is google.XX/url.... then we rewrite to the search result page url
- elseif ($this->getReferrerName() == 'Google'
- && strpos($this->details['referer_url'], '/url')
- ) {
- $refUrl = @parse_url($this->details['referer_url']);
- if (isset($refUrl['host'])) {
- $url = SearchEngine::getInstance()->getBackLinkFromUrlAndKeyword('http://google.com', $this->getKeyword());
- $url = str_replace('google.com', $refUrl['host'], $url);
-
- return $url;
- }
- }
- }
-
if (UrlHelper::isLookLikeUrl($this->details['referer_url'])) {
return $this->details['referer_url'];
}
@@ -77,7 +69,7 @@ class Visitor
return null;
}
- public function getKeywordPosition()
+ protected function getKeywordPosition()
{
if ($this->getReferrerType() == 'search'
&& strpos($this->getReferrerName(), 'Google') !== false
@@ -98,12 +90,12 @@ class Visitor
return null;
}
- public function getReferrerName()
+ protected function getReferrerName()
{
return urldecode($this->details['referer_name']);
}
- public function getSearchEngineUrl()
+ protected function getSearchEngineUrl()
{
if ($this->getReferrerType() == 'search'
&& !empty($this->details['referer_name'])
@@ -115,7 +107,7 @@ class Visitor
return null;
}
- public function getSearchEngineIcon()
+ protected function getSearchEngineIcon()
{
$searchEngineUrl = $this->getSearchEngineUrl();
@@ -126,5 +118,4 @@ class Visitor
return null;
}
-
} \ No newline at end of file
diff --git a/plugins/Referrers/templates/_visitorDetails.twig b/plugins/Referrers/templates/_visitorDetails.twig
new file mode 100644
index 0000000000..e3b03a2aba
--- /dev/null
+++ b/plugins/Referrers/templates/_visitorDetails.twig
@@ -0,0 +1,35 @@
+<div class="visitorReferrer {{ visitInfo.getColumn('referrerType') }}">
+ {% if visitInfo.getColumn('referrerType') == 'website' %}
+ <span>{{ 'Referrers_ColumnWebsite'|translate }}:</span>
+ <a href="{{ visitInfo.getColumn('referrerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitInfo.getColumn('referrerUrl') }}"
+ style="text-decoration:underline;">
+ {{ visitInfo.getColumn('referrerName') }}
+ </a>
+ {% endif %}
+ {% if visitInfo.getColumn('referrerType') == 'campaign' %}
+ <span>{{ 'Referrers_ColumnCampaign'|translate }}: {{ visitInfo.getColumn('referrerName') }}
+ {% if visitInfo.getColumn('referrerKeyword') is not empty %} - {{ visitInfo.getColumn('referrerKeyword') }}{% endif %}</span>
+ {% endif %}
+ {% if visitInfo.getColumn('referrerType') == 'search' %}
+ {%- set keywordNotDefined = 'General_NotDefined'|translate('General_ColumnKeyword'|translate) -%}
+ {%- set showKeyword = visitInfo.getColumn('referrerKeyword') is not empty and visitInfo.getColumn('referrerKeyword') != keywordNotDefined -%}
+ {% if visitInfo.getColumn('referrerSearchEngineIcon') %}
+ <img width="16" src="{{ visitInfo.getColumn('referrerSearchEngineIcon') }}" alt="{{ visitInfo.getColumn('referrerName') }}"/>
+ {% endif %}
+ <span {% if not showKeyword %}title="{{ keywordNotDefined }}" class="visitorLogTooltip"{% endif %}>{{ visitInfo.getColumn('referrerName') }}</span>
+ {%- if showKeyword %}<span>, {{ 'Referrers_Keywords'|translate }}:</span>
+ <a href="{{ visitInfo.getColumn('referrerUrl') }}" rel="noreferrer" target="_blank" style="text-decoration:underline;">
+ "{{ visitInfo.getColumn('referrerKeyword') }}"</a>
+ {% endif %}
+ {% set keyword %}{{ visitInfo.getColumn('referrerKeyword') }}{% endset %}
+ {% set searchName %}{{ visitInfo.getColumn('referrerName') }}{% endset %}
+ {% set position %}#{{ visitInfo.getColumn('referrerKeywordPosition') }}{% endset %}
+ {% if visitInfo.getColumn('referrerKeywordPosition') %}
+ <span title='{{ 'Live_KeywordRankedOnSearchResultForThisVisitor'|translate(keyword,position,searchName) }}' class='visitorRank visitorLogTooltip'>
+ <span class='hash'>#</span>
+ {{ visitInfo.getColumn('referrerKeywordPosition') }}
+ </span>
+ {% endif %}
+ {% endif %}
+ {% if visitInfo.getColumn('referrerType') == 'direct' %}{{ 'Referrers_DirectEntry'|translate }}{% endif %}
+</div>
diff --git a/plugins/Resolution/Resolution.php b/plugins/Resolution/Resolution.php
index 5ab7692ccf..da5acd7579 100644
--- a/plugins/Resolution/Resolution.php
+++ b/plugins/Resolution/Resolution.php
@@ -8,28 +8,9 @@
*/
namespace Piwik\Plugins\Resolution;
-use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
-use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-
/**
*
*/
class Resolution extends \Piwik\Plugin
{
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
- );
- }
-
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['resolution'] = $instance->getResolution();
- }
}
diff --git a/plugins/Resolution/Visitor.php b/plugins/Resolution/VisitorDetails.php
index 47fd330868..d6ccedb0a5 100644
--- a/plugins/Resolution/Visitor.php
+++ b/plugins/Resolution/VisitorDetails.php
@@ -2,22 +2,22 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\Resolution;
-class Visitor
-{
- private $details = array();
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
- public function __construct($details)
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
{
- $this->details = $details;
+ $visitor['resolution'] = $this->getResolution();
}
- function getResolution()
+ protected function getResolution()
{
if (!array_key_exists('config_resolution', $this->details)) {
return null;
diff --git a/plugins/UserCountry/ProfileSummary/LocationSummary.php b/plugins/UserCountry/ProfileSummary/LocationSummary.php
new file mode 100644
index 0000000000..2aee622b09
--- /dev/null
+++ b/plugins/UserCountry/ProfileSummary/LocationSummary.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\UserCountry\ProfileSummary;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugins\Live;
+use Piwik\Plugins\Live\ProfileSummary\ProfileSummaryAbstract;
+use Piwik\Url;
+use Piwik\View;
+
+/**
+ * Class LocationSummary
+ *
+ * @api
+ */
+class LocationSummary extends ProfileSummaryAbstract
+{
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return Piwik::translate('UserCountry_Location');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function render()
+ {
+ if (empty($this->profile['countries'])) {
+ return '';
+ }
+
+ $view = new View('@UserCountry/_profileSummary.twig');
+ $view->visitorData = $this->profile;
+
+ if (Common::getRequestVar('showMap', 1) == 1
+ && !empty($view->visitorData['hasLatLong'])
+ && \Piwik\Plugin\Manager::getInstance()->isPluginLoaded('UserCountryMap')
+ ) {
+ $view->userCountryMapUrl = $this->getUserCountryMapUrlForVisitorProfile();
+ }
+
+ return $view->render();
+ }
+
+ private function getUserCountryMapUrlForVisitorProfile()
+ {
+ $params = array(
+ 'module' => 'UserCountryMap',
+ 'action' => 'realtimeMap',
+ 'segment' => Live\Controller::getSegmentWithVisitorId(),
+ 'visitorId' => false,
+ 'changeVisitAlpha' => 0,
+ 'removeOldVisits' => 0,
+ 'realtimeWindow' => 'false',
+ 'showFooterMessage' => 0,
+ 'showDateTime' => 0,
+ 'doNotRefreshVisits' => 1
+ );
+ return Url::getCurrentQueryStringWithParametersModified($params);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOrder()
+ {
+ return 100;
+ }
+} \ No newline at end of file
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index 0e1fa71728..61e5925c37 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -37,27 +37,9 @@ class UserCountry extends \Piwik\Plugin
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'Tracker.setTrackerCacheGeneral' => 'setTrackerCacheGeneral',
'Insights.addReportToOverview' => 'addReportToInsightsOverview',
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails'
);
}
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['continent'] = $instance->getContinent();
- $visitor['continentCode'] = $instance->getContinentCode();
- $visitor['country'] = $instance->getCountryName();
- $visitor['countryCode'] = $instance->getCountryCode();
- $visitor['countryFlag'] = $instance->getCountryFlag();
- $visitor['region'] = $instance->getRegionName();
- $visitor['regionCode'] = $instance->getRegionCode();
- $visitor['city'] = $instance->getCityName();
- $visitor['location'] = $instance->getPrettyLocation();
- $visitor['latitude'] = $instance->getLatitude();
- $visitor['longitude'] = $instance->getLongitude();
- }
-
public function addReportToInsightsOverview(&$reports)
{
$reports['UserCountry_getCountry'] = array();
diff --git a/plugins/UserCountry/Visitor.php b/plugins/UserCountry/Visitor.php
deleted file mode 100644
index 2a64fcca0d..0000000000
--- a/plugins/UserCountry/Visitor.php
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\UserCountry;
-
-use Piwik\ArchiveProcessor;
-use Piwik\Common;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
-use Piwik\Plugins\UserCountry\LocationProvider;
-use Piwik\Tracker\Visit;
-use Piwik\Url;
-
-require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/functions.php';
-
-class Visitor
-{
- private $details = array();
-
- public function __construct($details)
- {
- $this->details = $details;
- }
-
- public function getCountryCode()
- {
- return $this->details['location_country'];
- }
-
- public function getCountryName()
- {
- return countryTranslate($this->getCountryCode());
- }
-
- public function getCountryFlag()
- {
- return getFlagFromCode($this->getCountryCode());
- }
-
- public function getContinent()
- {
- return continentTranslate($this->getContinentCode());
- }
-
- public function getContinentCode()
- {
- return Common::getContinent($this->details['location_country']);
- }
-
- public function getCityName()
- {
- if (!empty($this->details['location_city'])) {
- return $this->details['location_city'];
- }
-
- return null;
- }
-
- public function getRegionName()
- {
- $region = $this->getRegionCode();
- if ($region != '' && $region != Visit::UNKNOWN_CODE) {
- return GeoIp::getRegionNameFromCodes(
- $this->details['location_country'], $region);
- }
-
- return null;
- }
-
- public function getRegionCode()
- {
- return $this->details['location_region'];
- }
-
- public function getPrettyLocation()
- {
- $parts = array();
-
- $city = $this->getCityName();
- if (!empty($city)) {
- $parts[] = $city;
- }
- $region = $this->getRegionName();
- if (!empty($region)) {
- $parts[] = $region;
- }
-
- // add country & return concatenated result
- $parts[] = $this->getCountryName();
-
- return implode(', ', $parts);
- }
-
- public function getLatitude()
- {
- if (!empty($this->details['location_latitude'])) {
- return $this->details['location_latitude'];
- }
-
- return null;
- }
-
- public function getLongitude()
- {
- if (!empty($this->details['location_longitude'])) {
- return $this->details['location_longitude'];
- }
-
- return null;
- }
-} \ No newline at end of file
diff --git a/plugins/UserCountry/VisitorDetails.php b/plugins/UserCountry/VisitorDetails.php
new file mode 100644
index 0000000000..1458aea307
--- /dev/null
+++ b/plugins/UserCountry/VisitorDetails.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\UserCountry;
+
+use Piwik\Common;
+use Piwik\Plugins\Live;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
+use Piwik\Tracker\Visit;
+use Piwik\Url;
+use Piwik\View;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/functions.php';
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['continent'] = $this->getContinent();
+ $visitor['continentCode'] = $this->getContinentCode();
+ $visitor['country'] = $this->getCountryName();
+ $visitor['countryCode'] = $this->getCountryCode();
+ $visitor['countryFlag'] = $this->getCountryFlag();
+ $visitor['region'] = $this->getRegionName();
+ $visitor['regionCode'] = $this->getRegionCode();
+ $visitor['city'] = $this->getCityName();
+ $visitor['location'] = $this->getPrettyLocation();
+ $visitor['latitude'] = $this->getLatitude();
+ $visitor['longitude'] = $this->getLongitude();
+ }
+
+ protected function getCountryCode()
+ {
+ return $this->details['location_country'];
+ }
+
+ protected function getCountryName()
+ {
+ return countryTranslate($this->getCountryCode());
+ }
+
+ protected function getCountryFlag()
+ {
+ return getFlagFromCode($this->getCountryCode());
+ }
+
+ protected function getContinent()
+ {
+ return continentTranslate($this->getContinentCode());
+ }
+
+ protected function getContinentCode()
+ {
+ return Common::getContinent($this->details['location_country']);
+ }
+
+ protected function getCityName()
+ {
+ if (!empty($this->details['location_city'])) {
+ return $this->details['location_city'];
+ }
+
+ return null;
+ }
+
+ protected function getRegionName()
+ {
+ $region = $this->getRegionCode();
+ if ($region != '' && $region != Visit::UNKNOWN_CODE) {
+ return GeoIp::getRegionNameFromCodes(
+ $this->details['location_country'], $region);
+ }
+
+ return null;
+ }
+
+ protected function getRegionCode()
+ {
+ return $this->details['location_region'];
+ }
+
+ protected function getPrettyLocation()
+ {
+ $parts = array();
+
+ $city = $this->getCityName();
+ if (!empty($city)) {
+ $parts[] = $city;
+ }
+ $region = $this->getRegionName();
+ if (!empty($region)) {
+ $parts[] = $region;
+ }
+
+ // add country & return concatenated result
+ $parts[] = $this->getCountryName();
+
+ return implode(', ', $parts);
+ }
+
+ protected function getLatitude()
+ {
+ if (!empty($this->details['location_latitude'])) {
+ return $this->details['location_latitude'];
+ }
+
+ return null;
+ }
+
+ protected function getLongitude()
+ {
+ if (!empty($this->details['location_longitude'])) {
+ return $this->details['location_longitude'];
+ }
+
+ return null;
+ }
+
+
+ private $cities = array();
+ private $countries = array();
+ private $continents = array();
+
+ public function initProfile($visits, &$profile)
+ {
+ $this->cities = array();
+ $this->continents = array();
+ $this->countries = array();
+ $profile['hasLatLong'] = false;
+ }
+
+ public function handleProfileVisit($visit, &$profile)
+ {
+ // realtime map only checks for latitude
+ $hasLatitude = $visit->getColumn('latitude') !== false;
+ if ($hasLatitude) {
+ $profile['hasLatLong'] = true;
+ }
+
+ $countryCode = $visit->getColumn('countryCode');
+ if (!isset($this->countries[$countryCode])) {
+ $this->countries[$countryCode] = 0;
+ }
+ ++$this->countries[$countryCode];
+
+ $continentCode = $visit->getColumn('continentCode');
+ if (!isset($this->continents[$continentCode])) {
+ $this->continents[$continentCode] = 0;
+ }
+ ++$this->continents[$continentCode];
+
+ if ($countryCode && !array_key_exists($countryCode, $this->cities)) {
+ $this->cities[$countryCode] = array();
+ }
+ $city = $visit->getColumn('city');
+ if (!empty($city)) {
+ $this->cities[$countryCode][] = $city;
+ }
+ }
+
+ public function finalizeProfile($visits, &$profile)
+ {
+ // transform country/continents/search keywords into something that will look good in XML
+ $profile['countries'] = $profile['continents'] = array();
+
+ // sort by visit/action
+ asort($this->continents);
+ foreach ($this->continents as $continentCode => $nbVisits) {
+ $profile['continents'][] = array(
+ 'continent' => $continentCode,
+ 'nb_visits' => $nbVisits,
+ 'prettyName' => \Piwik\Plugins\UserCountry\continentTranslate($continentCode)
+ );
+ }
+
+ // sort by visit/action
+ asort($this->countries);
+
+ foreach ($this->countries as $countryCode => $nbVisits) {
+ $countryInfo = array(
+ 'country' => $countryCode,
+ 'nb_visits' => $nbVisits,
+ 'flag' => \Piwik\Plugins\UserCountry\getFlagFromCode($countryCode),
+ 'prettyName' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode)
+ );
+ if (!empty($this->cities[$countryCode])) {
+ $countryInfo['cities'] = array_unique($this->cities[$countryCode]);
+ }
+ $profile['countries'][] = $countryInfo;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/UserCountry/templates/_profileSummary.twig b/plugins/UserCountry/templates/_profileSummary.twig
new file mode 100644
index 0000000000..8e6b33ef96
--- /dev/null
+++ b/plugins/UserCountry/templates/_profileSummary.twig
@@ -0,0 +1,40 @@
+<div class="visitor-profile-summary visitor-profile-location">
+ <h1>{{ 'UserCountry_Location'|translate }}</h1>
+ <p>
+ {%- for entry in visitorData.countries -%}
+
+ {% set entryCity -%}
+ {% if entry.cities is defined and 1 == entry.cities|length and entry.cities|join -%}
+ {{ entry.cities|join }}
+ {%- elseif entry.cities is defined and 1 < entry.cities|length -%}
+ <span title="{{ entry.cities|join(', ') }}">{{ 'UserCountry_FromDifferentCities'|translate }}</span>
+ {%- endif %}
+ {%- endset %}
+
+ {% set entryVisits -%}
+ <strong>
+ {% if entry.nb_visits == 1 -%}
+ {{ 'General_OneVisit'|translate }}
+ {%- else -%}
+ {{ 'General_NVisits'|translate(entry.nb_visits) }}
+ {%- endif -%}
+ </strong>
+ {%- endset %}
+
+ {% set entryCountry -%}
+ {%- if entryCity -%}
+ {{ 'UserCountry_CityAndCountry'|translate(entryCity, entry.prettyName)|raw }}
+ {%- else -%}
+ {{ entry.prettyName }}
+ {%- endif -%}
+
+ &nbsp;<img height="16px" src="{{ entry.flag }}" title="{{ entry.prettyName }}"/>
+ {%- endset %}
+
+ {{- 'General_XFromY'|translate(entryVisits, entryCountry)|raw -}}{% if not loop.last %}, {% endif %}
+ {%- endfor %}
+ <a class="visitor-profile-show-map" href="#" {% if userCountryMapUrl|default('') is empty %}style="display:none"{% endif %}>({{ 'Live_ShowMap'|translate|replace({' ': '&nbsp;'})|raw }})</a> <img class="loadingPiwik" style="display:none;" src="plugins/Morpheus/images/loading-blue.gif"/>
+ </p>
+ <div class="visitor-profile-map" style="display:none" data-href="{{ userCountryMapUrl|default('') }}">
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/UserLanguage/UserLanguage.php b/plugins/UserLanguage/UserLanguage.php
index 3238ac11de..ea29eeb6d7 100644
--- a/plugins/UserLanguage/UserLanguage.php
+++ b/plugins/UserLanguage/UserLanguage.php
@@ -16,24 +16,6 @@ use Piwik\FrontController;
*/
class UserLanguage extends \Piwik\Plugin
{
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
- );
- }
-
- public function extendVisitorDetails(&$visitor, $details)
- {
- $instance = new Visitor($details);
-
- $visitor['languageCode'] = $instance->getLanguageCode();
- $visitor['language'] = $instance->getLanguage();
- }
-
public function postLoad()
{
Piwik::addAction('Template.footerUserCountry', array('Piwik\Plugins\UserLanguage\UserLanguage', 'footerUserCountry'));
diff --git a/plugins/UserLanguage/Visitor.php b/plugins/UserLanguage/VisitorDetails.php
index 26e8a36ec8..ba9122030f 100644
--- a/plugins/UserLanguage/Visitor.php
+++ b/plugins/UserLanguage/VisitorDetails.php
@@ -2,29 +2,30 @@
/**
* Piwik - free/libre analytics platform
*
- * @link http://piwik.org
+ * @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\UserLanguage;
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+
require_once PIWIK_INCLUDE_PATH . '/plugins/UserLanguage/functions.php';
-class Visitor
+class VisitorDetails extends VisitorDetailsAbstract
{
- private $details = array();
-
- public function __construct($details)
+ public function extendVisitorDetails(&$visitor)
{
- $this->details = $details;
+ $visitor['languageCode'] = $this->getLanguageCode();
+ $visitor['language'] = $this->getLanguage();
}
- public function getLanguageCode()
+ protected function getLanguageCode()
{
return $this->details['location_browser_lang'];
}
- public function getLanguage()
+ protected function getLanguage()
{
return languageTranslate($this->details['location_browser_lang']);
}
diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php
index 5b1c256ce7..39ac47d536 100644
--- a/plugins/VisitTime/VisitTime.php
+++ b/plugins/VisitTime/VisitTime.php
@@ -11,20 +11,4 @@ namespace Piwik\Plugins\VisitTime;
// empty plugin definition, otherwise plugin won't be installed during test run
class VisitTime extends \Piwik\Plugin
{
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
- );
- }
-
- public function extendVisitorDetails(&$visitor, $details)
- {
- $visitor['visitLocalTime'] = $details['visitor_localtime'];
- $visitor['visitLocalHour'] = date('G', strtotime('2012-12-21 ' . $details['visitor_localtime']));
- }
-
}
diff --git a/plugins/VisitTime/VisitorDetails.php b/plugins/VisitTime/VisitorDetails.php
new file mode 100644
index 0000000000..eb40686832
--- /dev/null
+++ b/plugins/VisitTime/VisitorDetails.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\VisitTime;
+
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['visitLocalTime'] = $this->details['visitor_localtime'];
+ $visitor['visitLocalHour'] = date('G', strtotime('2012-12-21 ' . $this->details['visitor_localtime']));
+ }
+} \ No newline at end of file
diff --git a/plugins/VisitorInterest/VisitorDetails.php b/plugins/VisitorInterest/VisitorDetails.php
new file mode 100644
index 0000000000..62f0b99f3e
--- /dev/null
+++ b/plugins/VisitorInterest/VisitorDetails.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\VisitorInterest;
+
+use Piwik\Plugins\Live\VisitorDetailsAbstract;
+
+class VisitorDetails extends VisitorDetailsAbstract
+{
+ public function extendVisitorDetails(&$visitor)
+ {
+ $visitor['daysSinceLastVisit'] = $this->details['visitor_days_since_last'];
+ }
+} \ No newline at end of file
diff --git a/plugins/VisitorInterest/VisitorInterest.php b/plugins/VisitorInterest/VisitorInterest.php
index f135e12923..1a624d4cdb 100644
--- a/plugins/VisitorInterest/VisitorInterest.php
+++ b/plugins/VisitorInterest/VisitorInterest.php
@@ -17,17 +17,6 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
class VisitorInterest extends \Piwik\Plugin
{
-
- /**
- * @see Piwik\Plugin::registerEvents
- */
- public function registerEvents()
- {
- return array(
- 'Live.getAllVisitorDetails' => 'extendVisitorDetails',
- );
- }
-
function postLoad()
{
Piwik::addAction('Template.footerVisitsFrequency', array('Piwik\Plugins\VisitorInterest\VisitorInterest', 'footerVisitsFrequency'));
@@ -37,10 +26,4 @@ class VisitorInterest extends \Piwik\Plugin
{
$out .= FrontController::getInstance()->fetchDispatch('VisitorInterest', 'index');
}
-
- public function extendVisitorDetails(&$visitor, $details)
- {
- $visitor['daysSinceLastVisit'] = $details['visitor_days_since_last'];
- }
-
}