add icons for Character groups
This commit is contained in:
commit
2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions
605
www/analytics/plugins/Transitions/API.php
Normal file
605
www/analytics/plugins/Transitions/API.php
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Plugins\Transitions;
|
||||
|
||||
use Exception;
|
||||
use Piwik\ArchiveProcessor;
|
||||
use Piwik\Common;
|
||||
use Piwik\DataAccess\LogAggregator;
|
||||
use Piwik\DataArray;
|
||||
use Piwik\DataTable\Manager;
|
||||
use Piwik\DataTable\Row;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Metrics;
|
||||
use Piwik\Period;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\Actions\Actions;
|
||||
use Piwik\Plugins\Actions\ArchivingHelper;
|
||||
use Piwik\RankingQuery;
|
||||
use Piwik\Segment;
|
||||
use Piwik\SegmentExpression;
|
||||
use Piwik\Site;
|
||||
use Piwik\Tracker\Action;
|
||||
use Piwik\Tracker\PageUrl;
|
||||
use Piwik\Tracker\TableLogAction;
|
||||
|
||||
/**
|
||||
* @method static \Piwik\Plugins\Transitions\API getInstance()
|
||||
*/
|
||||
class API extends \Piwik\Plugin\API
|
||||
{
|
||||
public function getTransitionsForPageTitle($pageTitle, $idSite, $period, $date, $segment = false, $limitBeforeGrouping = false)
|
||||
{
|
||||
return $this->getTransitionsForAction($pageTitle, 'title', $idSite, $period, $date, $segment, $limitBeforeGrouping);
|
||||
}
|
||||
|
||||
public function getTransitionsForPageUrl($pageUrl, $idSite, $period, $date, $segment = false, $limitBeforeGrouping = false)
|
||||
{
|
||||
return $this->getTransitionsForAction($pageUrl, 'url', $idSite, $period, $date, $segment, $limitBeforeGrouping);
|
||||
}
|
||||
|
||||
/**
|
||||
* General method to get transitions for an action
|
||||
*
|
||||
* @param $actionName
|
||||
* @param $actionType "url"|"title"
|
||||
* @param $idSite
|
||||
* @param $period
|
||||
* @param $date
|
||||
* @param bool $segment
|
||||
* @param bool $limitBeforeGrouping
|
||||
* @param string $parts
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getTransitionsForAction($actionName, $actionType, $idSite, $period, $date,
|
||||
$segment = false, $limitBeforeGrouping = false, $parts = 'all')
|
||||
{
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
// get idaction of the requested action
|
||||
$idaction = $this->deriveIdAction($actionName, $actionType);
|
||||
if ($idaction < 0) {
|
||||
throw new Exception('NoDataForAction');
|
||||
}
|
||||
|
||||
// prepare log aggregator
|
||||
$segment = new Segment($segment, $idSite);
|
||||
$site = new Site($idSite);
|
||||
$period = Period::factory($period, $date);
|
||||
$params = new ArchiveProcessor\Parameters($site, $period, $segment);
|
||||
$logAggregator = new LogAggregator($params);
|
||||
|
||||
// prepare the report
|
||||
$report = array(
|
||||
'date' => Period::factory($period->getLabel(), $date)->getLocalizedShortString()
|
||||
);
|
||||
|
||||
$partsArray = explode(',', $parts);
|
||||
if ($parts == 'all' || in_array('internalReferrers', $partsArray)) {
|
||||
$this->addInternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping);
|
||||
}
|
||||
if ($parts == 'all' || in_array('followingActions', $partsArray)) {
|
||||
$includeLoops = $parts != 'all' && !in_array('internalReferrers', $partsArray);
|
||||
$this->addFollowingActions($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops);
|
||||
}
|
||||
if ($parts == 'all' || in_array('externalReferrers', $partsArray)) {
|
||||
$this->addExternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping);
|
||||
}
|
||||
|
||||
// derive the number of exits from the other metrics
|
||||
if ($parts == 'all') {
|
||||
$report['pageMetrics']['exits'] = $report['pageMetrics']['pageviews']
|
||||
- $this->getTotalTransitionsToFollowingActions()
|
||||
- $report['pageMetrics']['loops'];
|
||||
}
|
||||
|
||||
// replace column names in the data tables
|
||||
$reportNames = array(
|
||||
'previousPages' => true,
|
||||
'previousSiteSearches' => false,
|
||||
'followingPages' => true,
|
||||
'followingSiteSearches' => false,
|
||||
'outlinks' => true,
|
||||
'downloads' => true
|
||||
);
|
||||
foreach ($reportNames as $reportName => $replaceLabel) {
|
||||
if (isset($report[$reportName])) {
|
||||
$columnNames = array(Metrics::INDEX_NB_ACTIONS => 'referrals');
|
||||
if ($replaceLabel) {
|
||||
$columnNames[Metrics::INDEX_NB_ACTIONS] = 'referrals';
|
||||
}
|
||||
$report[$reportName]->filter('ReplaceColumnNames', array($columnNames));
|
||||
}
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the action ID from the request action name and type.
|
||||
*/
|
||||
private function deriveIdAction($actionName, $actionType)
|
||||
{
|
||||
$actionsPlugin = new Actions;
|
||||
switch ($actionType) {
|
||||
case 'url':
|
||||
$originalActionName = $actionName;
|
||||
$actionName = Common::unsanitizeInputValue($actionName);
|
||||
$id = TableLogAction::getIdActionFromSegment($actionName, 'idaction_url', SegmentExpression::MATCH_EQUAL, 'pageUrl');
|
||||
|
||||
if ($id < 0) {
|
||||
// an example where this is needed is urls containing < or >
|
||||
$actionName = $originalActionName;
|
||||
$id = TableLogAction::getIdActionFromSegment($actionName, 'idaction_url', SegmentExpression::MATCH_EQUAL, 'pageUrl');
|
||||
}
|
||||
|
||||
return $id;
|
||||
|
||||
case 'title':
|
||||
$id = TableLogAction::getIdActionFromSegment($actionName, 'idaction_name', SegmentExpression::MATCH_EQUAL, 'pageTitle');
|
||||
|
||||
if ($id < 0) {
|
||||
$unknown = ArchivingHelper::getUnknownActionName(Action::TYPE_PAGE_TITLE);
|
||||
if (trim($actionName) == trim($unknown)) {
|
||||
$id = TableLogAction::getIdActionFromSegment('', 'idaction_name', SegmentExpression::MATCH_EQUAL, 'pageTitle');
|
||||
}
|
||||
}
|
||||
|
||||
return $id;
|
||||
|
||||
default:
|
||||
throw new Exception('Unknown action type');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the internal referrers to the report:
|
||||
* previous pages and previous site searches
|
||||
*
|
||||
* @param LogAggregator $logAggregator
|
||||
* @param $report
|
||||
* @param $idaction
|
||||
* @param string $actionType
|
||||
* @param $limitBeforeGrouping
|
||||
* @throws Exception
|
||||
*/
|
||||
private function addInternalReferrers($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping)
|
||||
{
|
||||
|
||||
$data = $this->queryInternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping);
|
||||
|
||||
if ($data['pageviews'] == 0) {
|
||||
throw new Exception('NoDataForAction');
|
||||
}
|
||||
|
||||
$report['previousPages'] = & $data['previousPages'];
|
||||
$report['previousSiteSearches'] = & $data['previousSiteSearches'];
|
||||
$report['pageMetrics']['loops'] = $data['loops'];
|
||||
$report['pageMetrics']['pageviews'] = $data['pageviews'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the following actions to the report:
|
||||
* following pages, downloads, outlinks
|
||||
*
|
||||
* @param LogAggregator $logAggregator
|
||||
* @param $report
|
||||
* @param $idaction
|
||||
* @param string $actionType
|
||||
* @param $limitBeforeGrouping
|
||||
* @param boolean $includeLoops
|
||||
*/
|
||||
private function addFollowingActions($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops = false)
|
||||
{
|
||||
|
||||
$data = $this->queryFollowingActions(
|
||||
$idaction, $actionType, $logAggregator, $limitBeforeGrouping, $includeLoops);
|
||||
|
||||
foreach ($data as $tableName => $table) {
|
||||
$report[$tableName] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the following actions (following pages, site searches, outlinks, downloads)
|
||||
*
|
||||
* @param $idaction
|
||||
* @param $actionType
|
||||
* @param LogAggregator $logAggregator
|
||||
* @param $limitBeforeGrouping
|
||||
* @param $includeLoops
|
||||
* @return array(followingPages:DataTable, outlinks:DataTable, downloads:DataTable)
|
||||
*/
|
||||
protected function queryFollowingActions($idaction, $actionType, LogAggregator $logAggregator,
|
||||
$limitBeforeGrouping = false, $includeLoops = false)
|
||||
{
|
||||
$types = array();
|
||||
|
||||
if ($actionType != 'title') {
|
||||
// specific setup for page urls
|
||||
$types[Action::TYPE_PAGE_URL] = 'followingPages';
|
||||
$dimension = 'IF( idaction_url IS NULL, idaction_name, idaction_url )';
|
||||
// site search referrers are logged with url=NULL
|
||||
// when we find one, we have to join on name
|
||||
$joinLogActionColumn = $dimension;
|
||||
$selects = array('log_action.name', 'log_action.url_prefix', 'log_action.type');
|
||||
} else {
|
||||
// specific setup for page titles:
|
||||
$types[Action::TYPE_PAGE_TITLE] = 'followingPages';
|
||||
// join log_action on name and url and pick depending on url type
|
||||
// the table joined on url is log_action1
|
||||
$joinLogActionColumn = array('idaction_url', 'idaction_name');
|
||||
$dimension = '
|
||||
CASE
|
||||
' /* following site search */ . '
|
||||
WHEN log_link_visit_action.idaction_url IS NULL THEN log_action2.idaction
|
||||
' /* following page view: use page title */ . '
|
||||
WHEN log_action1.type = ' . Action::TYPE_PAGE_URL . ' THEN log_action2.idaction
|
||||
' /* following download or outlink: use url */ . '
|
||||
ELSE log_action1.idaction
|
||||
END
|
||||
';
|
||||
$selects = array(
|
||||
'CASE
|
||||
' /* following site search */ . '
|
||||
WHEN log_link_visit_action.idaction_url IS NULL THEN log_action2.name
|
||||
' /* following page view: use page title */ . '
|
||||
WHEN log_action1.type = ' . Action::TYPE_PAGE_URL . ' THEN log_action2.name
|
||||
' /* following download or outlink: use url */ . '
|
||||
ELSE log_action1.name
|
||||
END AS `name`',
|
||||
'CASE
|
||||
' /* following site search */ . '
|
||||
WHEN log_link_visit_action.idaction_url IS NULL THEN log_action2.type
|
||||
' /* following page view: use page title */ . '
|
||||
WHEN log_action1.type = ' . Action::TYPE_PAGE_URL . ' THEN log_action2.type
|
||||
' /* following download or outlink: use url */ . '
|
||||
ELSE log_action1.type
|
||||
END AS `type`',
|
||||
'NULL AS `url_prefix`'
|
||||
);
|
||||
}
|
||||
|
||||
// these types are available for both titles and urls
|
||||
$types[Action::TYPE_SITE_SEARCH] = 'followingSiteSearches';
|
||||
$types[Action::TYPE_OUTLINK] = 'outlinks';
|
||||
$types[Action::TYPE_DOWNLOAD] = 'downloads';
|
||||
|
||||
$rankingQuery = new RankingQuery($limitBeforeGrouping ? $limitBeforeGrouping : $this->limitBeforeGrouping);
|
||||
$rankingQuery->addLabelColumn(array('name', 'url_prefix'));
|
||||
$rankingQuery->partitionResultIntoMultipleGroups('type', array_keys($types));
|
||||
|
||||
$type = $this->getColumnTypeSuffix($actionType);
|
||||
$where = 'log_link_visit_action.idaction_' . $type . '_ref = ' . intval($idaction);
|
||||
if (!$includeLoops) {
|
||||
$where .= ' AND (log_link_visit_action.idaction_' . $type . ' IS NULL OR '
|
||||
. 'log_link_visit_action.idaction_' . $type . ' != ' . intval($idaction) . ')';
|
||||
}
|
||||
|
||||
$metrics = array(Metrics::INDEX_NB_ACTIONS);
|
||||
$data = $logAggregator->queryActionsByDimension(array($dimension), $where, $selects, $metrics, $rankingQuery, $joinLogActionColumn);
|
||||
|
||||
$dataTables = $this->makeDataTablesFollowingActions($types, $data);
|
||||
|
||||
return $dataTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about external referrers (i.e. search engines, websites & campaigns)
|
||||
*
|
||||
* @param $idaction
|
||||
* @param $actionType
|
||||
* @param Logaggregator $logAggregator
|
||||
* @param $limitBeforeGrouping
|
||||
* @return DataTable
|
||||
*/
|
||||
protected function queryExternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping = false)
|
||||
{
|
||||
$rankingQuery = new RankingQuery($limitBeforeGrouping ? $limitBeforeGrouping : $this->limitBeforeGrouping);
|
||||
|
||||
// we generate a single column that contains the interesting data for each referrer.
|
||||
// the reason we cannot group by referer_* becomes clear when we look at search engine keywords.
|
||||
// referer_url contains the url from the search engine, referer_keyword the keyword we want to
|
||||
// group by. when we group by both, we don't get a single column for the keyword but instead
|
||||
// one column per keyword + search engine url. this way, we could not get the top keywords using
|
||||
// the ranking query.
|
||||
$dimensions = array('referrer_data', 'referer_type');
|
||||
$rankingQuery->addLabelColumn('referrer_data');
|
||||
$selects = array(
|
||||
'CASE log_visit.referer_type
|
||||
WHEN ' . Common::REFERRER_TYPE_DIRECT_ENTRY . ' THEN \'\'
|
||||
WHEN ' . Common::REFERRER_TYPE_SEARCH_ENGINE . ' THEN log_visit.referer_keyword
|
||||
WHEN ' . Common::REFERRER_TYPE_WEBSITE . ' THEN log_visit.referer_url
|
||||
WHEN ' . Common::REFERRER_TYPE_CAMPAIGN . ' THEN CONCAT(log_visit.referer_name, \' \', log_visit.referer_keyword)
|
||||
END AS `referrer_data`');
|
||||
|
||||
// get one limited group per referrer type
|
||||
$rankingQuery->partitionResultIntoMultipleGroups('referer_type', array(
|
||||
Common::REFERRER_TYPE_DIRECT_ENTRY,
|
||||
Common::REFERRER_TYPE_SEARCH_ENGINE,
|
||||
Common::REFERRER_TYPE_WEBSITE,
|
||||
Common::REFERRER_TYPE_CAMPAIGN
|
||||
));
|
||||
|
||||
$type = $this->getColumnTypeSuffix($actionType);
|
||||
$where = 'visit_entry_idaction_' . $type . ' = ' . intval($idaction);
|
||||
|
||||
$metrics = array(Metrics::INDEX_NB_VISITS);
|
||||
$data = $logAggregator->queryVisitsByDimension($dimensions, $where, $selects, $metrics, $rankingQuery);
|
||||
|
||||
$referrerData = array();
|
||||
$referrerSubData = array();
|
||||
|
||||
foreach ($data as $referrerType => &$subData) {
|
||||
$referrerData[$referrerType] = array(Metrics::INDEX_NB_VISITS => 0);
|
||||
if ($referrerType != Common::REFERRER_TYPE_DIRECT_ENTRY) {
|
||||
$referrerSubData[$referrerType] = array();
|
||||
}
|
||||
|
||||
foreach ($subData as &$row) {
|
||||
if ($referrerType == Common::REFERRER_TYPE_SEARCH_ENGINE && empty($row['referrer_data'])) {
|
||||
$row['referrer_data'] = \Piwik\Plugins\Referrers\API::LABEL_KEYWORD_NOT_DEFINED;
|
||||
}
|
||||
|
||||
$referrerData[$referrerType][Metrics::INDEX_NB_VISITS] += $row[Metrics::INDEX_NB_VISITS];
|
||||
|
||||
$label = $row['referrer_data'];
|
||||
if ($label) {
|
||||
$referrerSubData[$referrerType][$label] = array(
|
||||
Metrics::INDEX_NB_VISITS => $row[Metrics::INDEX_NB_VISITS]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = new DataArray($referrerData, $referrerSubData);
|
||||
return $array->asDataTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about internal referrers (previous pages & loops, i.e. page refreshes)
|
||||
*
|
||||
* @param $idaction
|
||||
* @param $actionType
|
||||
* @param LogAggregator $logAggregator
|
||||
* @param $limitBeforeGrouping
|
||||
* @return array(previousPages:DataTable, loops:integer)
|
||||
*/
|
||||
protected function queryInternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping = false)
|
||||
{
|
||||
$keyIsOther = 0;
|
||||
$keyIsPageUrlAction = 1;
|
||||
$keyIsSiteSearchAction = 2;
|
||||
|
||||
$rankingQuery = new RankingQuery($limitBeforeGrouping ? $limitBeforeGrouping : $this->limitBeforeGrouping);
|
||||
$rankingQuery->addLabelColumn(array('name', 'url_prefix'));
|
||||
$rankingQuery->setColumnToMarkExcludedRows('is_self');
|
||||
$rankingQuery->partitionResultIntoMultipleGroups('action_partition', array($keyIsOther, $keyIsPageUrlAction, $keyIsSiteSearchAction));
|
||||
|
||||
$type = $this->getColumnTypeSuffix($actionType);
|
||||
$mainActionType = Action::TYPE_PAGE_URL;
|
||||
$dimension = 'idaction_url_ref';
|
||||
|
||||
if ($actionType == 'title') {
|
||||
$mainActionType = Action::TYPE_PAGE_TITLE;
|
||||
$dimension = 'idaction_name_ref';
|
||||
}
|
||||
|
||||
$selects = array(
|
||||
'log_action.name',
|
||||
'log_action.url_prefix',
|
||||
'CASE WHEN log_link_visit_action.idaction_' . $type . '_ref = ' . intval($idaction) . ' THEN 1 ELSE 0 END AS `is_self`',
|
||||
'CASE
|
||||
WHEN log_action.type = ' . $mainActionType . ' THEN ' . $keyIsPageUrlAction . '
|
||||
WHEN log_action.type = ' . Action::TYPE_SITE_SEARCH . ' THEN ' . $keyIsSiteSearchAction .'
|
||||
ELSE ' . $keyIsOther . '
|
||||
END AS `action_partition`'
|
||||
);
|
||||
|
||||
$where = ' log_link_visit_action.idaction_' . $type . ' = ' . intval($idaction);
|
||||
|
||||
if ($dimension == 'idaction_url_ref') {
|
||||
// site search referrers are logged with url_ref=NULL
|
||||
// when we find one, we have to join on name_ref
|
||||
$dimension = 'IF( idaction_url_ref IS NULL, idaction_name_ref, idaction_url_ref )';
|
||||
$joinLogActionOn = $dimension;
|
||||
} else {
|
||||
$joinLogActionOn = $dimension;
|
||||
}
|
||||
$metrics = array(Metrics::INDEX_NB_ACTIONS);
|
||||
$data = $logAggregator->queryActionsByDimension(array($dimension), $where, $selects, $metrics, $rankingQuery, $joinLogActionOn);
|
||||
|
||||
$loops = 0;
|
||||
$nbPageviews = 0;
|
||||
$previousPagesDataTable = new DataTable;
|
||||
if (isset($data['result'][$keyIsPageUrlAction])) {
|
||||
foreach ($data['result'][$keyIsPageUrlAction] as &$page) {
|
||||
$nbActions = intval($page[Metrics::INDEX_NB_ACTIONS]);
|
||||
$previousPagesDataTable->addRow(new Row(array(
|
||||
Row::COLUMNS => array(
|
||||
'label' => $this->getPageLabel($page, Action::TYPE_PAGE_URL),
|
||||
Metrics::INDEX_NB_ACTIONS => $nbActions
|
||||
)
|
||||
)));
|
||||
$nbPageviews += $nbActions;
|
||||
}
|
||||
}
|
||||
|
||||
$previousSearchesDataTable = new DataTable;
|
||||
if (isset($data['result'][$keyIsSiteSearchAction])) {
|
||||
foreach ($data['result'][$keyIsSiteSearchAction] as &$search) {
|
||||
$nbActions = intval($search[Metrics::INDEX_NB_ACTIONS]);
|
||||
$previousSearchesDataTable->addRow(new Row(array(
|
||||
Row::COLUMNS => array(
|
||||
'label' => $search['name'],
|
||||
Metrics::INDEX_NB_ACTIONS => $nbActions
|
||||
)
|
||||
)));
|
||||
$nbPageviews += $nbActions;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['result'][0])) {
|
||||
foreach ($data['result'][0] as &$referrer) {
|
||||
$nbPageviews += intval($referrer[Metrics::INDEX_NB_ACTIONS]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($data['excludedFromLimit'])) {
|
||||
$loops += intval($data['excludedFromLimit'][0][Metrics::INDEX_NB_ACTIONS]);
|
||||
$nbPageviews += $loops;
|
||||
}
|
||||
|
||||
return array(
|
||||
'pageviews' => $nbPageviews,
|
||||
'previousPages' => $previousPagesDataTable,
|
||||
'previousSiteSearches' => $previousSearchesDataTable,
|
||||
'loops' => $loops
|
||||
);
|
||||
}
|
||||
|
||||
private function getPageLabel(&$pageRecord, $type)
|
||||
{
|
||||
if ($type == Action::TYPE_PAGE_TITLE) {
|
||||
$label = $pageRecord['name'];
|
||||
if (empty($label)) {
|
||||
$label = ArchivingHelper::getUnknownActionName(Action::TYPE_PAGE_TITLE);
|
||||
}
|
||||
return $label;
|
||||
}
|
||||
|
||||
if ($type == Action::TYPE_OUTLINK || $type == Action::TYPE_DOWNLOAD) {
|
||||
return PageUrl::reconstructNormalizedUrl($pageRecord['name'], $pageRecord['url_prefix']);
|
||||
}
|
||||
|
||||
return $pageRecord['name'];
|
||||
}
|
||||
|
||||
private function getColumnTypeSuffix($actionType)
|
||||
{
|
||||
if ($actionType == 'title') {
|
||||
return 'name';
|
||||
}
|
||||
return 'url';
|
||||
}
|
||||
|
||||
private $limitBeforeGrouping = 5;
|
||||
private $totalTransitionsToFollowingActions = 0;
|
||||
|
||||
/**
|
||||
* Get the sum of all transitions to following actions (pages, outlinks, downloads).
|
||||
* Only works if queryFollowingActions() has been used directly before.
|
||||
*/
|
||||
protected function getTotalTransitionsToFollowingActions()
|
||||
{
|
||||
return $this->totalTransitionsToFollowingActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the external referrers to the report:
|
||||
* direct entries, websites, campaigns, search engines
|
||||
*
|
||||
* @param LogAggregator $logAggregator
|
||||
* @param $report
|
||||
* @param $idaction
|
||||
* @param string $actionType
|
||||
* @param $limitBeforeGrouping
|
||||
*/
|
||||
private function addExternalReferrers($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping)
|
||||
{
|
||||
|
||||
$data = $this->queryExternalReferrers(
|
||||
$idaction, $actionType, $logAggregator, $limitBeforeGrouping);
|
||||
|
||||
$report['pageMetrics']['entries'] = 0;
|
||||
$report['referrers'] = array();
|
||||
foreach ($data->getRows() as $row) {
|
||||
$referrerId = $row->getColumn('label');
|
||||
$visits = $row->getColumn(Metrics::INDEX_NB_VISITS);
|
||||
if ($visits) {
|
||||
// load details (i.e. subtables)
|
||||
$details = array();
|
||||
if ($idSubTable = $row->getIdSubDataTable()) {
|
||||
$subTable = Manager::getInstance()->getTable($idSubTable);
|
||||
foreach ($subTable->getRows() as $subRow) {
|
||||
$details[] = array(
|
||||
'label' => $subRow->getColumn('label'),
|
||||
'referrals' => $subRow->getColumn(Metrics::INDEX_NB_VISITS)
|
||||
);
|
||||
}
|
||||
}
|
||||
$report['referrers'][] = array(
|
||||
'label' => $this->getReferrerLabel($referrerId),
|
||||
'shortName' => \Piwik\Plugins\Referrers\getReferrerTypeFromShortName($referrerId),
|
||||
'visits' => $visits,
|
||||
'details' => $details
|
||||
);
|
||||
$report['pageMetrics']['entries'] += $visits;
|
||||
}
|
||||
}
|
||||
|
||||
// if there's no data for referrers, ResponseBuilder::handleMultiDimensionalArray
|
||||
// does not detect the multi dimensional array and the data is rendered differently, which
|
||||
// causes an exception.
|
||||
if (count($report['referrers']) == 0) {
|
||||
$report['referrers'][] = array(
|
||||
'label' => $this->getReferrerLabel(Common::REFERRER_TYPE_DIRECT_ENTRY),
|
||||
'shortName' => \Piwik\Plugins\Referrers\getReferrerTypeLabel(Common::REFERRER_TYPE_DIRECT_ENTRY),
|
||||
'visits' => 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getReferrerLabel($referrerId)
|
||||
{
|
||||
switch ($referrerId) {
|
||||
case Common::REFERRER_TYPE_DIRECT_ENTRY:
|
||||
return Controller::getTranslation('directEntries');
|
||||
case Common::REFERRER_TYPE_SEARCH_ENGINE:
|
||||
return Controller::getTranslation('fromSearchEngines');
|
||||
case Common::REFERRER_TYPE_WEBSITE:
|
||||
return Controller::getTranslation('fromWebsites');
|
||||
case Common::REFERRER_TYPE_CAMPAIGN:
|
||||
return Controller::getTranslation('fromCampaigns');
|
||||
default:
|
||||
return Piwik::translate('General_Others');
|
||||
}
|
||||
}
|
||||
|
||||
public function getTranslations()
|
||||
{
|
||||
$controller = new Controller();
|
||||
return $controller->getTranslations();
|
||||
}
|
||||
|
||||
protected function makeDataTablesFollowingActions($types, $data)
|
||||
{
|
||||
$this->totalTransitionsToFollowingActions = 0;
|
||||
$dataTables = array();
|
||||
foreach ($types as $type => $recordName) {
|
||||
$dataTable = new DataTable;
|
||||
if (isset($data[$type])) {
|
||||
foreach ($data[$type] as &$record) {
|
||||
$actions = intval($record[Metrics::INDEX_NB_ACTIONS]);
|
||||
$dataTable->addRow(new Row(array(
|
||||
Row::COLUMNS => array(
|
||||
'label' => $this->getPageLabel($record, $type),
|
||||
Metrics::INDEX_NB_ACTIONS => $actions
|
||||
)
|
||||
)));
|
||||
$this->totalTransitionsToFollowingActions += $actions;
|
||||
}
|
||||
}
|
||||
$dataTables[$recordName] = $dataTable;
|
||||
}
|
||||
return $dataTables;
|
||||
}
|
||||
}
|
||||
89
www/analytics/plugins/Transitions/Controller.php
Normal file
89
www/analytics/plugins/Transitions/Controller.php
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\Transitions;
|
||||
|
||||
use Piwik\Piwik;
|
||||
use Piwik\View;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Controller extends \Piwik\Plugin\Controller
|
||||
{
|
||||
/**
|
||||
* Since the metric translations are taken from different plugins,
|
||||
* it makes the rest of the code easier to read and maintain when we
|
||||
* use this indirection to map between the metrics and the actual
|
||||
* translation keys.
|
||||
*/
|
||||
private static $metricTranslations = array(
|
||||
'pageviewsInline' => 'VisitsSummary_NbPageviewsDescription',
|
||||
'loopsInline' => 'Transitions_LoopsInline',
|
||||
'fromPreviousPages' => 'Transitions_FromPreviousPages',
|
||||
'fromPreviousPagesInline' => 'Transitions_FromPreviousPagesInline',
|
||||
'fromPreviousSiteSearches' => 'Transitions_FromPreviousSiteSearches',
|
||||
'fromPreviousSiteSearchesInline' => 'Transitions_FromPreviousSiteSearchesInline',
|
||||
'fromSearchEngines' => 'Transitions_FromSearchEngines',
|
||||
'fromSearchEnginesInline' => 'Referrers_TypeSearchEngines',
|
||||
'fromWebsites' => 'Transitions_FromWebsites',
|
||||
'fromWebsitesInline' => 'Referrers_TypeWebsites',
|
||||
'fromCampaigns' => 'Transitions_FromCampaigns',
|
||||
'fromCampaignsInline' => 'Referrers_TypeCampaigns',
|
||||
'directEntries' => 'Transitions_DirectEntries',
|
||||
'directEntriesInline' => 'Referrers_TypeDirectEntries',
|
||||
'toFollowingPages' => 'Transitions_ToFollowingPages',
|
||||
'toFollowingPagesInline' => 'Transitions_ToFollowingPagesInline',
|
||||
'toFollowingSiteSearches' => 'Transitions_ToFollowingSiteSearches',
|
||||
'toFollowingSiteSearchesInline' => 'Transitions_ToFollowingSiteSearchesInline',
|
||||
'downloads' => 'General_Downloads',
|
||||
'downloadsInline' => 'VisitsSummary_NbDownloadsDescription',
|
||||
'outlinks' => 'General_Outlinks',
|
||||
'outlinksInline' => 'VisitsSummary_NbOutlinksDescription',
|
||||
'exits' => 'General_ColumnExits',
|
||||
'exitsInline' => 'Transitions_ExitsInline',
|
||||
'bouncesInline' => 'Transitions_BouncesInline'
|
||||
);
|
||||
|
||||
/**
|
||||
* Translations that are added to JS
|
||||
*/
|
||||
private static $jsTranslations = array(
|
||||
'XOfY' => 'Transitions_XOutOfYVisits',
|
||||
'XOfAllPageviews' => 'Transitions_XOfAllPageviews',
|
||||
'NoDataForAction' => 'Transitions_NoDataForAction',
|
||||
'NoDataForActionDetails' => 'Transitions_NoDataForActionDetails',
|
||||
'NoDataForActionBack' => 'Transitions_ErrorBack',
|
||||
'ShareOfAllPageviews' => 'Transitions_ShareOfAllPageviews',
|
||||
'DateRange' => 'General_DateRange'
|
||||
);
|
||||
|
||||
public static function getTranslation($key)
|
||||
{
|
||||
return Piwik::translate(self::$metricTranslations[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method of the plugin.
|
||||
* It is triggered from the Transitions data table action.
|
||||
*/
|
||||
public function renderPopover()
|
||||
{
|
||||
$view = new View('@Transitions/renderPopover');
|
||||
$view->translations = $this->getTranslations();
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function getTranslations()
|
||||
{
|
||||
$translations = self::$metricTranslations + self::$jsTranslations;
|
||||
foreach ($translations as &$message) {
|
||||
$message = Piwik::translate($message);
|
||||
}
|
||||
return $translations;
|
||||
}
|
||||
}
|
||||
43
www/analytics/plugins/Transitions/Transitions.php
Normal file
43
www/analytics/plugins/Transitions/Transitions.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Plugins\Transitions;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Transitions extends \Piwik\Plugin
|
||||
{
|
||||
/**
|
||||
* @see Piwik\Plugin::getListHooksRegistered
|
||||
*/
|
||||
public function getListHooksRegistered()
|
||||
{
|
||||
return array(
|
||||
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
|
||||
);
|
||||
}
|
||||
|
||||
public function getStylesheetFiles(&$stylesheets)
|
||||
{
|
||||
$stylesheets[] = 'plugins/Transitions/stylesheets/transitions.less';
|
||||
}
|
||||
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = 'plugins/Transitions/javascripts/transitions.js';
|
||||
}
|
||||
|
||||
public function getClientSideTranslationKeys(&$translationKeys)
|
||||
{
|
||||
$translationKeys[] = 'General_TransitionsRowActionTooltipTitle';
|
||||
$translationKeys[] = 'General_TransitionsRowActionTooltip';
|
||||
}
|
||||
}
|
||||
BIN
www/analytics/plugins/Transitions/images/transitions_icon.png
Executable file
BIN
www/analytics/plugins/Transitions/images/transitions_icon.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 643 B |
BIN
www/analytics/plugins/Transitions/images/transitions_icon_hover.png
Executable file
BIN
www/analytics/plugins/Transitions/images/transitions_icon_hover.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 647 B |
1553
www/analytics/plugins/Transitions/javascripts/transitions.js
Normal file
1553
www/analytics/plugins/Transitions/javascripts/transitions.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// transitions colors
|
||||
//
|
||||
|
||||
// colors for entries gradients
|
||||
.transition-entries[data-name=light] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-entries[data-name=dark] {
|
||||
color: #BACFE8;
|
||||
}
|
||||
|
||||
.transition-entries[data-name=light-highlighted] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-entries[data-name=dark-highlighted] {
|
||||
color: #FAD293;
|
||||
}
|
||||
|
||||
// colors for exits gradients
|
||||
.transition-exits[data-name=light] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-exits[data-name=dark] {
|
||||
color: #BACFE8;
|
||||
}
|
||||
|
||||
.transition-exits[data-name=light-highlighted] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-exits[data-name=dark-highlighted] {
|
||||
color: #FAD293;
|
||||
}
|
||||
|
||||
// background gradients colors
|
||||
.transition-background[data-name=light] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-background[data-name=dark] {
|
||||
color: #BACFE8;
|
||||
}
|
||||
|
||||
.transition-background[data-name=light-highlighted] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.transition-background[data-name=dark-highlighted] {
|
||||
color: #FAD293;
|
||||
}
|
||||
|
||||
// closed group gradient colors
|
||||
.transition-closed-group[data-name=light] {
|
||||
color: #DDE4ED;
|
||||
}
|
||||
|
||||
.transition-closed-group[data-name=dark] {
|
||||
color: #9BBADE;
|
||||
}
|
||||
|
||||
.transition-closed-group[data-name=light-highlighted] {
|
||||
color: #FAE2C0;
|
||||
}
|
||||
|
||||
.transition-closed-group[data-name=dark-highlighted] {
|
||||
color: #FAD293;
|
||||
}
|
||||
|
||||
// items gradient colors
|
||||
.transition-items[data-name=light] {
|
||||
color: #E3DFD1;
|
||||
}
|
||||
|
||||
.transition-items[data-name=dark] {
|
||||
color: #E8E4D5;
|
||||
}
|
||||
|
||||
// 'others' gradients colors
|
||||
.transition-others[data-name=light] {
|
||||
color: #F5F3EB;
|
||||
}
|
||||
|
||||
.transition-others[data-name=dark] {
|
||||
color: #E8E4D5;
|
||||
}
|
||||
|
||||
// loop gradient colors
|
||||
.transition-loops[data-name=light] {
|
||||
color: #F5F3EB;
|
||||
}
|
||||
|
||||
.transition-loops[data-name=dark] {
|
||||
color: #E8E4D5;
|
||||
}
|
||||
198
www/analytics/plugins/Transitions/stylesheets/transitions.less
Normal file
198
www/analytics/plugins/Transitions/stylesheets/transitions.less
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
@import "_transitionColors";
|
||||
|
||||
#Transitions_Container {
|
||||
position: relative;
|
||||
z-index: 1500;
|
||||
height: 550px;
|
||||
text-align: left;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.Transitions_Canvas_Container {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#Transitions_Canvas_Background_Left {
|
||||
z-index: 1501;
|
||||
}
|
||||
|
||||
#Transitions_Canvas_Background_Right {
|
||||
z-index: 1502;
|
||||
}
|
||||
|
||||
#Transitions_Canvas_Left {
|
||||
z-index: 1503;
|
||||
}
|
||||
|
||||
#Transitions_Canvas_Right {
|
||||
z-index: 1504;
|
||||
}
|
||||
|
||||
#Transitions_Canvas_Loops {
|
||||
z-index: 1505;
|
||||
}
|
||||
|
||||
.Transitions_Text {
|
||||
color: black;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0); /* without this, IE9 triggers hover only on the text, not the box */
|
||||
z-index: 1506;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
word-wrap: break-word;
|
||||
text-align: left;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#Transitions_CenterBox {
|
||||
margin: 27px 0 0 345px;
|
||||
width: 208px;
|
||||
height: 373px;
|
||||
background: #f7f7f7;
|
||||
border: 1px solid #a9a399;
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: 0px 0px 9px 0px #999;
|
||||
-moz-box-shadow: 0px 0px 9px 0px #999;
|
||||
box-shadow: 0px 0px 9px 0px #999;
|
||||
z-index: 1507;
|
||||
}
|
||||
|
||||
#Transitions_CenterBox h2 {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
padding: 10px;
|
||||
border-bottom: 1px dotted #a9a399;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
color: #255792;
|
||||
}
|
||||
|
||||
.Transitions_Pageviews {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Transitions_OutgoingTraffic {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics {
|
||||
padding: 15px 10px 0 10px;
|
||||
display: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics table td {
|
||||
padding: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics table td.Transitions_Percentage {
|
||||
padding-right: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#Transitions_CenterBox h3 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin: 15px 0 7px 0;
|
||||
padding: 0;
|
||||
color: #7E7363;
|
||||
}
|
||||
|
||||
#Transitions_Loops {
|
||||
margin: 445px 0 0 346px;
|
||||
width: 208px;
|
||||
text-align: center;
|
||||
line-height: 25px;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
z-index: 1506;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics p {
|
||||
margin: 0 0 3px 0;
|
||||
padding: 0;
|
||||
cursor: default;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics p.Transitions_Margin {
|
||||
margin-bottom: 11px;
|
||||
}
|
||||
|
||||
.Transitions_CenterBoxMetrics .Transitions_Highlighted {
|
||||
color: #E87500;
|
||||
}
|
||||
|
||||
span.Transitions_Metric {
|
||||
font-weight: bold;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.Transitions_Value0 {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.Transitions_TitleOfOpenGroup {
|
||||
font-size: 12px;
|
||||
color: #E87500;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextLeft,
|
||||
.Transitions_BoxTextRight {
|
||||
width: 165px;
|
||||
height: 42px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextRight {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextLeft.Transitions_HasBackground,
|
||||
.Transitions_BoxTextRight.Transitions_HasBackground {
|
||||
background-repeat: no-repeat;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextLeft.Transitions_HasBackground {
|
||||
background-position: 0 1px;
|
||||
width: 175px;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextLeft.Transitions_HasBackground span {
|
||||
display: block;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextRight.Transitions_HasBackground {
|
||||
background-position: right 1px;
|
||||
}
|
||||
|
||||
.Transitions_BoxTextRight.Transitions_HasBackground span {
|
||||
display: block;
|
||||
padding-right: 17px;
|
||||
}
|
||||
|
||||
.Transitions_CurveTextLeft,
|
||||
.Transitions_CurveTextRight {
|
||||
color: #255792;
|
||||
font-weight: bold;
|
||||
width: 34px;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
body .ui-tooltip.Transitions_Tooltip_Small {
|
||||
font-size: 11px;
|
||||
padding: 3px 5px 3px 6px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.Transitions_SingleLine {
|
||||
font-size: 12px;
|
||||
height: 21px;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<div id="Transitions_Container">
|
||||
<div id="Transitions_CenterBox" class="Transitions_Text">
|
||||
<h2></h2>
|
||||
|
||||
<div class="Transitions_CenterBoxMetrics">
|
||||
<p class="Transitions_Pageviews Transitions_Margin">{{ translations.pageviewsInline|translate }}</p>
|
||||
|
||||
<div class="Transitions_IncomingTraffic">
|
||||
<h3>{{ 'Transitions_IncomingTraffic'|translate }}</h3>
|
||||
|
||||
<p class="Transitions_PreviousPages">{{ translations.fromPreviousPagesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_PreviousSiteSearches">{{ translations.fromPreviousSiteSearchesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_SearchEngines">{{ translations.fromSearchEnginesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_Websites">{{ translations.fromWebsitesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_Campaigns">{{ translations.fromCampaignsInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_DirectEntries">{{ translations.directEntriesInline|translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="Transitions_OutgoingTraffic">
|
||||
<h3>{{ 'Transitions_OutgoingTraffic'|translate }}</h3>
|
||||
|
||||
<p class="Transitions_FollowingPages">{{ translations.toFollowingPagesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_FollowingSiteSearches">{{ translations.toFollowingSiteSearchesInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_Downloads">{{ translations.downloadsInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_Outlinks">{{ translations.outlinksInline|translate }}</p>
|
||||
|
||||
<p class="Transitions_Exits">{{ translations.exitsInline|translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="Transitions_Loops" class="Transitions_Text">
|
||||
{{ translations.loopsInline|translate }}
|
||||
</div>
|
||||
<div id="Transitions_Canvas_Background_Left" class="Transitions_Canvas_Container"></div>
|
||||
<div id="Transitions_Canvas_Background_Right" class="Transitions_Canvas_Container"></div>
|
||||
<div id="Transitions_Canvas_Left" class="Transitions_Canvas_Container"></div>
|
||||
<div id="Transitions_Canvas_Right" class="Transitions_Canvas_Container"></div>
|
||||
<div id="Transitions_Canvas_Loops" class="Transitions_Canvas_Container"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var Piwik_Transitions_Translations = {
|
||||
{% for internalKey, translation in translations %}
|
||||
"{{ internalKey }}": "{{ translation }}",
|
||||
{% endfor %}
|
||||
"": ""
|
||||
};
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue