diff options
author | mattpiwik <matthieu.aubry@gmail.com> | 2012-10-07 10:43:22 +0400 |
---|---|---|
committer | mattpiwik <matthieu.aubry@gmail.com> | 2012-10-07 10:43:22 +0400 |
commit | 4d3a3b3204da368e809d374f9471b3bb9af883fd (patch) | |
tree | 6c3830686ee79425a259bc03603399dbd781c126 | |
parent | ac5425ec48878249080de5624f5b235b40059204 (diff) |
Refs #3332
* Transition works for Page titles with hierarchy (eg "$Category / $name")
* URL metadata:
* is only available on non Summary rows.
* It is now set to the page with highest number of visits, when page names do overwrite.
* However now, by default we do track keep hash tags and we do not aggregate them in one page URL.
* Refs #3232 Will be nice to have, to allow to "not track fragment" by default. See stub processUrlFragment().
More to do: Admin UI, Tests w/ and wo/ hash tags, w/ Capital letter in hostname
* URL being tracked, and URL read from the logs (for backward compatibility) are now cleaned: hostname is lowered,
and URL Fragment is kept/removed.
git-svn-id: http://dev.piwik.org/svn/trunk@7113 59fd770c-687e-43c8-a1e3-f5a4ff64c105
-rw-r--r-- | core/API/DataTableManipulator/LabelFilter.php | 1 | ||||
-rw-r--r-- | core/DataTable.php | 5 | ||||
-rw-r--r-- | core/DataTable/Row.php | 16 | ||||
-rw-r--r-- | core/Tracker/Action.php | 61 | ||||
-rw-r--r-- | plugins/API/API.php | 47 | ||||
-rw-r--r-- | plugins/Actions/ArchivingHelper.php | 52 | ||||
-rw-r--r-- | plugins/CoreHome/templates/datatable_rowactions.js | 8 | ||||
-rw-r--r-- | plugins/Transitions/API.php | 7 | ||||
-rw-r--r-- | plugins/Transitions/Transitions.php | 9 |
9 files changed, 147 insertions, 59 deletions
diff --git a/core/API/DataTableManipulator/LabelFilter.php b/core/API/DataTableManipulator/LabelFilter.php index 4b56f4b17b..2614b7e89f 100644 --- a/core/API/DataTableManipulator/LabelFilter.php +++ b/core/API/DataTableManipulator/LabelFilter.php @@ -53,7 +53,6 @@ class Piwik_API_DataTableManipulator_LabelFilter extends Piwik_API_DataTableMani { return $dataTable; } - foreach ($this->getLabelVariations($label) as $label) { $label = explode(self::SEPARATOR_RECURSIVE_LABEL, $label); diff --git a/core/DataTable.php b/core/DataTable.php index 322300af63..915eed3f07 100644 --- a/core/DataTable.php +++ b/core/DataTable.php @@ -1438,8 +1438,11 @@ class Piwik_DataTable $row->setColumns(array('label' => $segment) + $missingRowColumns); $next = $table->addRow($row); + if ($next !== $row) // if the row wasn't added, the table is full { + // Summary row, has no metadata + $next->deleteMetadata(); return array($next, $i); } } @@ -1459,6 +1462,8 @@ class Piwik_DataTable $table = new Piwik_DataTable(); $table->setMaximumAllowedRows($maxSubtableRows); $next->setSubtable($table); + // Summary row, has no metadata + $next->deleteMetadata(); } } } diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php index 1476a78691..55b20dea63 100644 --- a/core/DataTable/Row.php +++ b/core/DataTable/Row.php @@ -492,7 +492,21 @@ class Piwik_DataTable_Row $this->setColumn( $columnToSumName, $newValue); } } - $this->c[self::METADATA] = $rowToSum->c[self::METADATA]; + + + if( !empty($rowToSum->c[self::METADATA]) ) + { + // We shall update metadata, and keep the metadata with the _most visits or pageviews_, rather than first or last seen + $visits = max($rowToSum->getColumn(Piwik_Archive::INDEX_NB_VISITS),$rowToSum->getColumn(Piwik_Archive::INDEX_NB_ACTIONS)); + + if(!($this instanceof Piwik_DataTable_Row_DataTableSummary) + && ( ( $visits && $visits > max($this->getColumn(Piwik_Archive::INDEX_NB_VISITS),$this->getColumn(Piwik_Archive::INDEX_NB_ACTIONS)) ) + || empty($this->c[self::METADATA]) ) ) + { + $this->c[self::METADATA] = $rowToSum->c[self::METADATA]; + } + } + } /** diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php index de4e9a26cf..4e0c355ddc 100644 --- a/core/Tracker/Action.php +++ b/core/Tracker/Action.php @@ -25,6 +25,7 @@ interface Piwik_Tracker_Action_Interface { const TYPE_ECOMMERCE_ITEM_SKU = 5; const TYPE_ECOMMERCE_ITEM_NAME = 6; const TYPE_ECOMMERCE_ITEM_CATEGORY = 7; + const TYPE_SITE_SEARCH = 8; public function setRequest($requestArray); public function setIdSite( $idSite ); @@ -64,7 +65,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface * Map URL prefixes to integers. * @see self::normalizeUrl(), self::reconstructNormalizedUrl() */ - static private $urlPrefixMap = array( + static public $urlPrefixMap = array( 'http://www.' => 1, 'http://' => 0, 'https://www.' => 3, @@ -105,9 +106,23 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface $map = array_flip(self::$urlPrefixMap); if ($prefixId !== null && isset($map[$prefixId])) { - return $map[$prefixId].$url; + $fullUrl = $map[$prefixId].$url; } - return $url; + else + { + $fullUrl = $url; + } + + // Clean up host & hash tags, for URLs + $parsedUrl = @parse_url($fullUrl); + $parsedUrl = self::cleanupHostAndHashTag($parsedUrl); + $url = Piwik_Common::getParseUrlReverse($parsedUrl); + if(!empty($url)) + { + return $url; + } + + return $fullUrl; } @@ -226,6 +241,40 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface return $url; } + /** + * Will cleanup the hostname (some browser do not strolower the hostname), + * and deal ith the hash tag on incoming URLs based on website setting. + * + * @param $parsedUrl + * @return array + */ + static public function cleanupHostAndHashTag($parsedUrl) + { + if(empty($parsedUrl)) + { + return $parsedUrl; + } + if(!empty($parsedUrl['host'])) + { + $parsedUrl['host'] = mb_strtolower($parsedUrl['host'], 'UTF-8'); + } + + if(!empty($parsedUrl['fragment'])) + { + $parsedUrl['fragment'] = self::processUrlFragment($parsedUrl['fragment']); + } + + return $parsedUrl; + } + + public static function processUrlFragment($urlFragment) + { + //TOOD implement, read setting for this site +// return ''; + return $urlFragment; + } + + static public function excludeQueryParametersFromUrl($originalUrl, $idSite) { $website = Piwik_Common::getCacheWebsiteAttributes( $idSite ); @@ -233,7 +282,9 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface $parsedUrl = @parse_url($originalUrl); if(empty($parsedUrl['query'])) { - return $originalUrl; + $parsedUrl = self::cleanupHostAndHashTag($parsedUrl); + $url = Piwik_Common::getParseUrlReverse($parsedUrl); + return $url; } $campaignTrackingParameters = Piwik_Common::getCampaignParameters(); @@ -287,7 +338,9 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface } } $parsedUrl['query'] = substr($validQuery,0,-strlen($separator)); + $parsedUrl = self::cleanupHostAndHashTag($parsedUrl); $url = Piwik_Common::getParseUrlReverse($parsedUrl); + printDebug('Excluding parameters "'.implode(',',$excludedParameters).'" from URL'); if($originalUrl != $url) { diff --git a/plugins/API/API.php b/plugins/API/API.php index 5110c67b0a..6d68e2186b 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -1223,19 +1223,14 @@ class Piwik_API_API if (!$actualLabel) { - $actualLabel = $row->getColumn('label'); $logo = $row->getMetadata('logo'); - - if ( ($url = $row->getMetadata('url')) - && ($apiModule == 'Actions' - || ($apiModule == 'Referers' - && $apiAction == 'getWebsites')) - && $labelUseAbsoluteUrl - ) - { - $actualLabel = preg_replace(';^http(s)?://(www.)?;i', '', $url); - $urlFound = true; + + list($actualLabel, $urlFound) = $this->cleanUrlForLabel($row, $apiModule, $apiAction, $labelUseAbsoluteUrl); + if(empty($actualLabel)) + { + $actualLabel = $row->getColumn('label'); } + } // remove all columns that are not in the available metrics. @@ -1272,6 +1267,21 @@ class Piwik_API_API return $return; } + private function cleanUrlForLabel($row, $apiModule, $apiAction, $labelUseAbsoluteUrl) + { + $urlFound = $actualLabel = false; + if (($url = $row->getMetadata('url')) + && ($apiModule == 'Actions' + || ($apiModule == 'Referers' + && $apiAction == 'getWebsites')) + && $labelUseAbsoluteUrl + ) { + $actualLabel = preg_replace(';^http(s)?://(www.)?;i', '', $url); + $urlFound = true; + } + return array($actualLabel, $urlFound); + } + /** * @param $idSite * @param $period @@ -1491,25 +1501,18 @@ class Piwik_API_API $actualLabels[$labelIndex] = $columnLabel; } - // if url is available as metadata, use it (only for actions reports) - if ( ($url = $firstRow->getMetadata('url')) - && ($apiModule == 'Actions' - || ($apiModule == 'Referers' - && $apiAction == 'getWebsites')) - && $labelUseAbsoluteUrl - ) + list($actualLabel, $urlFound) = $this->cleanUrlForLabel($firstRow, $apiModule, $apiAction, $labelUseAbsoluteUrl); + if($actualLabel) { - $actualLabels[$labelIndex] = preg_replace(';^http(s)?://(www.)?;i', '', $url);; - $urlFound = true; + $actualLabels[$labelIndex] = $actualLabel; } - + // Forward the logo path to display logos in multi rows comparison $logos[$labelIndex] = $firstRow->getMetadata('logo'); break; } } - // if we have a recursive label and no url, use the path if (!$urlFound) { $actualLabels[$labelIndex] = str_replace(Piwik_API_DataTableManipulator_LabelFilter::SEPARATOR_RECURSIVE_LABEL, ' - ', $label); diff --git a/plugins/Actions/ArchivingHelper.php b/plugins/Actions/ArchivingHelper.php index 015a35ef3d..e7d0bad3bb 100644 --- a/plugins/Actions/ArchivingHelper.php +++ b/plugins/Actions/ArchivingHelper.php @@ -61,16 +61,16 @@ class Piwik_Actions_ArchivingHelper continue; } - $currentTable = self::getActionRow($actionName, $actionType, $urlPrefix, $actionsTablesByType); + $actionRow = self::getActionRow($actionName, $actionType, $urlPrefix, $actionsTablesByType); - self::setCachedActionRow($idaction, $actionType, $currentTable); + self::setCachedActionRow($idaction, $actionType, $actionRow); } else { - $currentTable = self::getCachedActionRow($row['idaction'], $row['type']); + $actionRow = self::getCachedActionRow($row['idaction'], $row['type']); // Action processed as "to skip" for some reasons - if($currentTable === false) + if($actionRow === false) { continue; } @@ -81,7 +81,7 @@ class Piwik_Actions_ArchivingHelper unset($row['idaction']); unset($row['url_prefix']); - if (is_null($currentTable)) + if (is_null($actionRow)) { continue; } @@ -92,33 +92,33 @@ class Piwik_Actions_ArchivingHelper // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page, // and in between the two the other visitor comes. // here we handle the case where there is already a row for this action name, if this is the case we add the value - if(($alreadyValue = $currentTable->getColumn($name)) !== false) + if(($alreadyValue = $actionRow->getColumn($name)) !== false) { - $currentTable->setColumn($name, $alreadyValue+$value); + $actionRow->setColumn($name, $alreadyValue+$value); } else { - $currentTable->addColumn($name, $value); + $actionRow->addColumn($name, $value); } } // if the exit_action was not recorded properly in the log_link_visit_action // there would be an error message when getting the nb_hits column // we must fake the record and add the columns - if($currentTable->getColumn(Piwik_Archive::INDEX_PAGE_NB_HITS) === false) + if($actionRow->getColumn(Piwik_Archive::INDEX_PAGE_NB_HITS) === false) { // to test this code: delete the entries in log_link_action_visit for // a given exit_idaction_url foreach(self::getDefaultRow()->getColumns() as $name => $value) { - $currentTable->addColumn($name, $value); + $actionRow->addColumn($name, $value); } } $rowsProcessed++; } - // just to make sure php copies the last $currentTable in the $parentTable array - $currentTable =& $actionsTablesByType; + // just to make sure php copies the last $actionRow in the $parentTable array + $actionRow =& $actionsTablesByType; return $rowsProcessed; } @@ -192,6 +192,7 @@ class Piwik_Actions_ArchivingHelper protected static function getActionRow( $actionName, $actionType, $urlPrefix=null, &$actionsTablesByType ) { // we work on the root table of the given TYPE (either ACTION_URL or DOWNLOAD or OUTLINK etc.) + /* @var Piwik_DataTable $currentTable */ $currentTable =& $actionsTablesByType[$actionType]; // check for ranking query cut-off @@ -209,20 +210,16 @@ class Piwik_Actions_ArchivingHelper $actionExplodedNames = self::getActionExplodedNames($actionName, $actionType, $urlPrefix); list($row, $level) = $currentTable->walkPath( $actionExplodedNames, self::getDefaultRowColumns(), self::$maximumRowsInSubDataTable); - + // if we didn't traverse the entire path, the table the action belongs to is full, so we // found a summary row. we don't set metadata on that row. - if ($level != count($actionExplodedNames)) + if ($level != count($actionExplodedNames) + || $actionType == Piwik_Tracker_Action::TYPE_ACTION_NAME) { return $row; } - - // if the action type is a URL type, set the url as metadata - if ($actionType != Piwik_Tracker_Action::TYPE_ACTION_NAME) - { - $row->setMetadata('url', Piwik_Tracker_Action::reconstructNormalizedUrl((string)$actionName, $urlPrefix)); - } - + $row->setMetadata('url', Piwik_Tracker_Action::reconstructNormalizedUrl((string)$actionName, $urlPrefix)); + return $row; } @@ -273,7 +270,7 @@ class Piwik_Actions_ArchivingHelper $isUrl = true; $urlHost = $matches[1]; $urlPath = $matches[2]; - $urlAnchor = $matches[3]; + $urlFragment = $matches[3]; } if($type == Piwik_Tracker_Action::TYPE_DOWNLOAD @@ -304,6 +301,15 @@ class Piwik_Actions_ArchivingHelper $categoryDelimiter = self::$actionUrlCategoryDelimiter; } + + if( $isUrl ) + { + $urlFragment = Piwik_Tracker_Action::processUrlFragment($urlFragment); + if(!empty($urlFragment)) { + $name .= '#' . $urlFragment; + } + } + if(empty($categoryDelimiter)) { return array( trim($name) ); @@ -446,7 +452,7 @@ class Piwik_Actions_ArchivingHelper /** * Creates a summary row for an Actions DataTable. * - * @return array + * @return Piwik_DataTable_Row */ private static function createSummaryRow() { diff --git a/plugins/CoreHome/templates/datatable_rowactions.js b/plugins/CoreHome/templates/datatable_rowactions.js index 34a5b2dd49..77666139ba 100644 --- a/plugins/CoreHome/templates/datatable_rowactions.js +++ b/plugins/CoreHome/templates/datatable_rowactions.js @@ -133,10 +133,12 @@ DataTable_RowAction.prototype.initTr = function(tr) { DataTable_RowAction.prototype.trigger = function(tr, e, subTableLabel) { var label = this.getLabelFromTr(tr); - // if we have received the event from the sub table, add the label + label = label.trim(); + // if we have received the event from the sub table, add the label if (subTableLabel) { - label += '>' + subTableLabel; - } + var separator = ' > '; // Piwik_API_DataTableManipulator_LabelFilter::SEPARATOR_RECURSIVE_LABEL + label += separator + subTableLabel.trim(); + } // handle sub tables in nested reports: forward to parent var subtable = tr.closest('table'); diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php index bb855bdb4c..c9bd0af82a 100644 --- a/plugins/Transitions/API.php +++ b/plugins/Transitions/API.php @@ -108,14 +108,17 @@ class Piwik_Transitions_API private function deriveIdAction($actionName, $actionType) { $actionsPlugin = new Piwik_Actions; - + $actionName = Piwik_Common::unsanitizeInputValue($actionName); switch ($actionType) { case 'url': - $actionName = Piwik_Common::unsanitizeInputValue($actionName); return $actionsPlugin->getIdActionFromSegment($actionName, 'idaction_url'); case 'title': + // Transitions is called with Page titles separated by > so we transform back + $actionName = explode(Piwik_API_DataTableManipulator_LabelFilter::SEPARATOR_RECURSIVE_LABEL, $actionName); + $actionName = array_map('trim', $actionName ); + $actionName = implode("/", $actionName); $id = $actionsPlugin->getIdActionFromSegment($actionName, 'idaction_name'); if ($id < 0) diff --git a/plugins/Transitions/Transitions.php b/plugins/Transitions/Transitions.php index f51fbd0139..593b67fc7b 100644 --- a/plugins/Transitions/Transitions.php +++ b/plugins/Transitions/Transitions.php @@ -210,7 +210,8 @@ class Piwik_Transitions extends Piwik_Plugin ); } - private function getPageLabel(&$pageRecord, $isTitle) { + private function getPageLabel(&$pageRecord, $isTitle) + { if ($isTitle) { $label = $pageRecord['name']; @@ -330,11 +331,13 @@ class Piwik_Transitions extends Piwik_Plugin * Get the sum of all transitions to following actions (pages, outlinks, downloads). * Only works if queryFollowingActions() has been used directly before. */ - public function getTotalTransitionsToFollowingActions() { + public function getTotalTransitionsToFollowingActions() + { return $this->totalTransitionsToFollowingActions; } - private function getColumnTypeSuffix($actionType) { + private function getColumnTypeSuffix($actionType) + { if ($actionType == 'title') { return 'name'; } |