add icons for Character groups
This commit is contained in:
commit
2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions
350
www/analytics/plugins/Insights/API.php
Normal file
350
www/analytics/plugins/Insights/API.php
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
<?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\Insights;
|
||||
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Date;
|
||||
use Piwik\Log;
|
||||
use Piwik\Period\Range;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\API\ProcessedReport;
|
||||
use Piwik\API\Request as ApiRequest;
|
||||
use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI;
|
||||
|
||||
/**
|
||||
* API for plugin Insights
|
||||
*
|
||||
* @method static \Piwik\Plugins\Insights\API getInstance()
|
||||
*/
|
||||
class API extends \Piwik\Plugin\API
|
||||
{
|
||||
/**
|
||||
* Include only 'movers' which are existing in the current and past report.
|
||||
*/
|
||||
const FILTER_BY_MOVERS = 'movers';
|
||||
|
||||
/**
|
||||
* Include only 'new' rows which were not existing in the past report.
|
||||
*/
|
||||
const FILTER_BY_NEW = 'new';
|
||||
|
||||
/**
|
||||
* Include only 'disappeared' rows which were existing in the past report but no longer in the current report.
|
||||
*/
|
||||
const FILTER_BY_DISAPPEARED = 'disappeared';
|
||||
|
||||
/**
|
||||
* @var Model
|
||||
*/
|
||||
private $model;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->model = new Model();
|
||||
}
|
||||
|
||||
private function getOverviewReports()
|
||||
{
|
||||
$reports = array();
|
||||
|
||||
/**
|
||||
* Triggered to gather all reports to be displayed in the "Insight" and "Movers And Shakers" overview reports.
|
||||
* Plugins that want to add new reports to the overview should subscribe to this event and add reports to the
|
||||
* incoming array. API parameters can be configured as an array optionally.
|
||||
*
|
||||
* **Example**
|
||||
*
|
||||
* public function addReportToInsightsOverview(&$reports)
|
||||
* {
|
||||
* $reports['Actions_getPageUrls'] = array();
|
||||
* $reports['Actions_getDownloads'] = array('flat' => 1, 'minGrowthPercent' => 60);
|
||||
* }
|
||||
*
|
||||
* @param array &$reports An array containing a report unique id as key and an array of API parameters as
|
||||
* values.
|
||||
*/
|
||||
Piwik::postEvent('Insights.addReportToOverview', array(&$reports));
|
||||
|
||||
return $reports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether insights can be generated for this date/period combination or not.
|
||||
* @param string $date eg 'today', '2012-12-12'
|
||||
* @param string $period eg 'day' or 'week'
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canGenerateInsights($date, $period)
|
||||
{
|
||||
Piwik::checkUserHasSomeViewAccess();
|
||||
|
||||
try {
|
||||
$model = new Model();
|
||||
$lastDate = $model->getLastDate($date, $period, 1);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($lastDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates insights for a set of reports. Plugins can add their own reports to be included in the insights
|
||||
* overview by listening to the {@hook Insights.addReportToOverview} event.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param bool|string $segment
|
||||
*
|
||||
* @return DataTable\Map A map containing a dataTable for each insight report. See {@link getInsights()} for more
|
||||
* information
|
||||
*/
|
||||
public function getInsightsOverview($idSite, $period, $date, $segment = false)
|
||||
{
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$defaultParams = array(
|
||||
'limitIncreaser' => 3,
|
||||
'limitDecreaser' => 3,
|
||||
'minImpactPercent' => 1,
|
||||
'minGrowthPercent' => 25,
|
||||
);
|
||||
|
||||
$map = $this->generateOverviewReport('getInsights', $idSite, $period, $date, $segment, $defaultParams);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the movers and shakers for a set of reports. Plugins can add their own reports to be included in this
|
||||
* overview by listening to the {@hook Insights.addReportToOverview} event.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param bool|string $segment
|
||||
*
|
||||
* @return DataTable\Map A map containing a dataTable for each movers and shakers report. See
|
||||
* {@link getMoversAndShakers()} for more information
|
||||
*/
|
||||
public function getMoversAndShakersOverview($idSite, $period, $date, $segment = false)
|
||||
{
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$defaultParams = array(
|
||||
'limitIncreaser' => 4,
|
||||
'limitDecreaser' => 4
|
||||
);
|
||||
|
||||
$map = $this->generateOverviewReport('getMoversAndShakers', $idSite, $period, $date, $segment, $defaultParams);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function generateOverviewReport($method, $idSite, $period, $date, $segment, array $defaultParams)
|
||||
{
|
||||
$tableManager = DataTable\Manager::getInstance();
|
||||
|
||||
/** @var DataTable[] $tables */
|
||||
$tables = array();
|
||||
foreach ($this->getOverviewReports() as $reportId => $reportParams) {
|
||||
if (!empty($reportParams)) {
|
||||
foreach ($defaultParams as $key => $defaultParam) {
|
||||
if (!array_key_exists($key, $reportParams)) {
|
||||
$reportParams[$key] = $defaultParam;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$firstTableId = $tableManager->getMostRecentTableId();
|
||||
$table = $this->requestApiMethod($method, $idSite, $period, $date, $reportId, $segment, $reportParams);
|
||||
$reportTableIds[] = $table->getId();
|
||||
$tableManager->deleteTablesExceptIgnored($reportTableIds, $firstTableId);
|
||||
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
$map = new DataTable\Map();
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$map->addTable($table, $table->getMetadata('reportName'));
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the movers and shakers of a given date / report combination. A mover and shakers has an higher impact
|
||||
* than other rows on average. For instance if a sites pageviews increase by 10% a page that increased by 40% at the
|
||||
* same time contributed significantly more to the success than the average of 10%.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param string $reportUniqueId eg 'Actions_getPageUrls'. An id like 'Goals_getVisitsUntilConversion_idGoal--4' works as well.
|
||||
* @param bool|string $segment
|
||||
* @param int $comparedToXPeriods
|
||||
* @param int $limitIncreaser Value '0' ignores all increasers
|
||||
* @param int $limitDecreaser Value '0' ignores all decreasers
|
||||
*
|
||||
* @return DataTable
|
||||
*
|
||||
* @throws \Exception In case a report having the given ID does not exist
|
||||
* @throws \Exception In case the report exists but does not return a dataTable
|
||||
*/
|
||||
public function getMoversAndShakers($idSite, $period, $date, $reportUniqueId, $segment = false,
|
||||
$comparedToXPeriods = 1, $limitIncreaser = 4, $limitDecreaser = 4)
|
||||
{
|
||||
Piwik::checkUserHasViewAccess(array($idSite));
|
||||
|
||||
$metric = 'nb_visits';
|
||||
$orderBy = InsightReport::ORDER_BY_ABSOLUTE;
|
||||
|
||||
$reportMetadata = $this->model->getReportByUniqueId($idSite, $reportUniqueId);
|
||||
|
||||
if (empty($reportMetadata)) {
|
||||
throw new \Exception('A report having the ID ' . $reportUniqueId . ' does not exist');
|
||||
}
|
||||
|
||||
$totalValue = $this->model->getTotalValue($idSite, $period, $date, $metric);
|
||||
$currentReport = $this->model->requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment);
|
||||
$this->checkReportIsValid($currentReport);
|
||||
|
||||
$lastDate = $this->model->getLastDate($date, $period, $comparedToXPeriods);
|
||||
$lastTotalValue = $this->model->getTotalValue($idSite, $period, $lastDate, $metric);
|
||||
$lastReport = $this->model->requestReport($idSite, $period, $lastDate, $reportUniqueId, $metric, $segment);
|
||||
$this->checkReportIsValid($lastReport);
|
||||
|
||||
$insight = new InsightReport();
|
||||
return $insight->generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates insights by comparing the report for a given date/period with a different date and calculating the
|
||||
* difference. The API can exclude rows which growth is not good enough or did not have enough impact.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param string $reportUniqueId eg 'Actions_getPageUrls'. An id like 'Goals_getVisitsUntilConversion_idGoal--4' works as well.
|
||||
* @param bool|string $segment
|
||||
* @param int $limitIncreaser Value '0' ignores all increasers
|
||||
* @param int $limitDecreaser Value '0' ignores all decreasers
|
||||
* @param string $filterBy By default all rows will be ignored. If given only 'movers', 'new' or 'disappeared' will be returned.
|
||||
* @param int $minImpactPercent The minimum impact in percent. Eg '2%' of 1000 visits means the change /
|
||||
* increase / decrease has to be at least 20 visits. Usually the '2%' are based on the total
|
||||
* amount of visits but for reports having way less visits the metric total is used. Eg A page
|
||||
* has 1000 visits but only 100 visits having keywords. In this case a minimum impact of '2%' evaluates to 2 and not 20.
|
||||
* @param int $minGrowthPercent The amount of percent a row has to increase or decrease at least compared to the previous period.
|
||||
* If value is '20' the growth has to be either at least '+20%' or '-20%' and lower.
|
||||
* @param int $comparedToXPeriods The report will be compared to X periods before.
|
||||
* @param string $orderBy Orders the rows by 'absolute', 'relative' or 'importance'.
|
||||
*
|
||||
* @return DataTable
|
||||
*
|
||||
* @throws \Exception In case a report having the given ID does not exist
|
||||
* @throws \Exception In case the report exists but does not return a dataTable
|
||||
*/
|
||||
public function getInsights(
|
||||
$idSite, $period, $date, $reportUniqueId, $segment = false, $limitIncreaser = 5, $limitDecreaser = 5,
|
||||
$filterBy = '', $minImpactPercent = 2, $minGrowthPercent = 20,
|
||||
$comparedToXPeriods = 1, $orderBy = 'absolute')
|
||||
{
|
||||
Piwik::checkUserHasViewAccess(array($idSite));
|
||||
|
||||
$metric = 'nb_visits';
|
||||
|
||||
$reportMetadata = $this->model->getReportByUniqueId($idSite, $reportUniqueId);
|
||||
|
||||
if (empty($reportMetadata)) {
|
||||
throw new \Exception('A report having the ID ' . $reportUniqueId . ' does not exist');
|
||||
}
|
||||
|
||||
$totalValue = $this->model->getTotalValue($idSite, $period, $date, $metric);
|
||||
$currentReport = $this->model->requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment);
|
||||
$this->checkReportIsValid($currentReport);
|
||||
|
||||
$lastDate = $this->model->getLastDate($date, $period, $comparedToXPeriods);
|
||||
$lastTotalValue = $this->model->getTotalValue($idSite, $period, $lastDate, $metric);
|
||||
$lastReport = $this->model->requestReport($idSite, $period, $lastDate, $reportUniqueId, $metric, $segment);
|
||||
$this->checkReportIsValid($lastReport);
|
||||
|
||||
$minGrowthPercentPositive = abs($minGrowthPercent);
|
||||
$minGrowthPercentNegative = -1 * $minGrowthPercentPositive;
|
||||
|
||||
$relevantTotal = $this->model->getRelevantTotalValue($currentReport, $metric, $totalValue);
|
||||
|
||||
$minMoversPercent = -1;
|
||||
$minNewPercent = -1;
|
||||
$minDisappearedPercent = -1;
|
||||
|
||||
switch ($filterBy) {
|
||||
case self::FILTER_BY_MOVERS:
|
||||
$minMoversPercent = $minImpactPercent;
|
||||
break;
|
||||
case self::FILTER_BY_NEW:
|
||||
$minNewPercent = $minImpactPercent;
|
||||
break;
|
||||
case self::FILTER_BY_DISAPPEARED:
|
||||
$minDisappearedPercent = $minImpactPercent;
|
||||
break;
|
||||
default:
|
||||
$minMoversPercent = $minImpactPercent;
|
||||
$minNewPercent = $minImpactPercent;
|
||||
$minDisappearedPercent = $minImpactPercent;
|
||||
}
|
||||
|
||||
$insight = new InsightReport();
|
||||
$table = $insight->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $relevantTotal, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser);
|
||||
$insight->markMoversAndShakers($table, $currentReport, $lastReport, $totalValue, $lastTotalValue);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function checkReportIsValid($report)
|
||||
{
|
||||
if (!($report instanceof DataTable)) {
|
||||
throw new \Exception('Insight can be only generated for reports returning a dataTable');
|
||||
}
|
||||
}
|
||||
|
||||
private function requestApiMethod($method, $idSite, $period, $date, $reportId, $segment, $additionalParams)
|
||||
{
|
||||
$params = array(
|
||||
'method' => 'Insights.' . $method,
|
||||
'idSite' => $idSite,
|
||||
'date' => $date,
|
||||
'period' => $period,
|
||||
'format' => 'original',
|
||||
'reportUniqueId' => $reportId,
|
||||
);
|
||||
|
||||
if (!empty($segment)) {
|
||||
$params['segment'] = $segment;
|
||||
}
|
||||
|
||||
if (!empty($additionalParams)) {
|
||||
foreach ($additionalParams as $key => $value) {
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$request = new ApiRequest($params);
|
||||
return $request->process();
|
||||
}
|
||||
|
||||
}
|
||||
84
www/analytics/plugins/Insights/Controller.php
Normal file
84
www/analytics/plugins/Insights/Controller.php
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?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\Insights;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\Insights\Visualizations\Insight;
|
||||
use Piwik\View;
|
||||
|
||||
/**
|
||||
* Insights Controller
|
||||
*/
|
||||
class Controller extends \Piwik\Plugin\Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$idSite = Common::getRequestVar('idSite', null, 'int');
|
||||
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
}
|
||||
|
||||
public function getInsightsOverview()
|
||||
{
|
||||
$view = $this->prepareWidgetView('insightsOverviewWidget.twig');
|
||||
$view->reports = $this->requestApiReport('getInsightsOverview');
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function getOverallMoversAndShakers()
|
||||
{
|
||||
$view = $this->prepareWidgetView('moversAndShakersOverviewWidget.twig');
|
||||
$view->reports = $this->requestApiReport('getMoversAndShakersOverview');
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
private function prepareWidgetView($template)
|
||||
{
|
||||
if (!$this->canGenerateInsights()) {
|
||||
|
||||
$view = new View('@Insights/cannotDisplayReport.twig');
|
||||
$this->setBasicVariablesView($view);
|
||||
return $view;
|
||||
}
|
||||
|
||||
$view = new View('@Insights/' . $template);
|
||||
$this->setBasicVariablesView($view);
|
||||
|
||||
$view->properties = array(
|
||||
'order_by' => InsightReport::ORDER_BY_ABSOLUTE
|
||||
);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function requestApiReport($apiReport)
|
||||
{
|
||||
if (!$this->canGenerateInsights()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$idSite = Common::getRequestVar('idSite', null, 'int');
|
||||
$period = Common::getRequestVar('period', null, 'string');
|
||||
$date = Common::getRequestVar('date', null, 'string');
|
||||
|
||||
return API::getInstance()->$apiReport($idSite, $period, $date);
|
||||
}
|
||||
|
||||
private function canGenerateInsights()
|
||||
{
|
||||
$period = Common::getRequestVar('period', null, 'string');
|
||||
$date = Common::getRequestVar('date', null, 'string');
|
||||
|
||||
return API::getInstance()->canGenerateInsights($date, $period);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?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\Insights\DataTable\Filter;
|
||||
|
||||
use Piwik\DataTable;
|
||||
|
||||
/**
|
||||
* Removes all rows whose value is too low.
|
||||
*/
|
||||
class ExcludeLowValue extends DataTable\BaseFilter
|
||||
{
|
||||
private $minimumValue;
|
||||
private $columnToRead;
|
||||
private $columnToCheckToBeTrue;
|
||||
|
||||
/**
|
||||
* @param DataTable $table
|
||||
* @param string $columnToRead
|
||||
* @param int $minimumValue
|
||||
* @param string $columnToCheckToBeTrue if set, we will delete a row only if this column evaluates to true. If
|
||||
* column does not evaluate to true we will not delete the row even if
|
||||
* the value is lower than the minimumValue.
|
||||
*/
|
||||
public function __construct($table, $columnToRead, $minimumValue, $columnToCheckToBeTrue = '')
|
||||
{
|
||||
$this->columnToRead = $columnToRead;
|
||||
$this->minimumValue = $minimumValue;
|
||||
$this->columnToCheckToBeTrue = $columnToCheckToBeTrue;
|
||||
}
|
||||
|
||||
public function filter($table)
|
||||
{
|
||||
if (!$this->minimumValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($table->getRows() as $key => $row) {
|
||||
|
||||
if ($this->columnToCheckToBeTrue && !$row->getColumn($this->columnToCheckToBeTrue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $row->getColumn($this->columnToRead);
|
||||
|
||||
if ($this->minimumValue > abs($value)) {
|
||||
$table->deleteRow($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
www/analytics/plugins/Insights/DataTable/Filter/Insight.php
Normal file
119
www/analytics/plugins/Insights/DataTable/Filter/Insight.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?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\Insights\DataTable\Filter;
|
||||
|
||||
use Piwik\DataTable;
|
||||
|
||||
class Insight extends DataTable\Filter\CalculateEvolutionFilter
|
||||
{
|
||||
private $considerMovers;
|
||||
private $considerNew;
|
||||
private $considerDisappeared;
|
||||
private $currentDataTable;
|
||||
|
||||
public function __construct($table, $currentDataTable, $pastDataTable, $columnToRead,
|
||||
$considerMovers, $considerNew, $considerDisappeared)
|
||||
{
|
||||
parent::__construct($table, $pastDataTable, 'growth', $columnToRead, $quotientPrecision = 1);
|
||||
|
||||
$this->currentDataTable = $currentDataTable;
|
||||
$this->considerMovers = $considerMovers;
|
||||
$this->considerNew = $considerNew;
|
||||
$this->considerDisappeared = $considerDisappeared;
|
||||
}
|
||||
|
||||
public function filter($table)
|
||||
{
|
||||
foreach ($this->currentDataTable->getRows() as $row) {
|
||||
$this->addRowIfNewOrMover($table, $row);
|
||||
}
|
||||
|
||||
if ($this->considerDisappeared) {
|
||||
foreach ($this->pastDataTable->getRows() as $row) {
|
||||
$this->addRowIfDisappeared($table, $row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addRowIfDisappeared(DataTable $table, DataTable\Row $row)
|
||||
{
|
||||
if ($this->getRowFromTable($this->currentDataTable, $row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newValue = 0;
|
||||
$oldValue = $row->getColumn($this->columnValueToRead);
|
||||
$difference = $newValue - $oldValue;
|
||||
|
||||
if ($oldValue == 0 && $newValue == 0) {
|
||||
$growthPercentage = '0%';
|
||||
} else {
|
||||
$growthPercentage = '-100%';
|
||||
}
|
||||
|
||||
$this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared = true);
|
||||
}
|
||||
|
||||
private function addRowIfNewOrMover(DataTable $table, DataTable\Row $row)
|
||||
{
|
||||
$pastRow = $this->getPastRowFromCurrent($row);
|
||||
|
||||
if (!$pastRow && !$this->considerNew) {
|
||||
return;
|
||||
} elseif ($pastRow && !$this->considerMovers) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isNew = false;
|
||||
$isMover = false;
|
||||
$isDisappeared = false;
|
||||
|
||||
if (!$pastRow) {
|
||||
$isNew = true;
|
||||
$oldValue = 0;
|
||||
} else {
|
||||
$isMover = true;
|
||||
$oldValue = $pastRow->getColumn($this->columnValueToRead);
|
||||
}
|
||||
|
||||
$difference = $this->getDividend($row);
|
||||
if ($difference === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newValue = $row->getColumn($this->columnValueToRead);
|
||||
$divisor = $this->getDivisor($row);
|
||||
|
||||
$growthPercentage = $this->formatValue($difference, $divisor);
|
||||
|
||||
$this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared, $isNew, $isMover);
|
||||
}
|
||||
|
||||
private function getRowFromTable(DataTable $table, DataTable\Row $row)
|
||||
{
|
||||
return $table->getRowFromLabel($row->getColumn('label'));
|
||||
}
|
||||
|
||||
private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $newValue, $oldValue, $difference, $disappeared = false, $isNew = false, $isMover = false)
|
||||
{
|
||||
$columns = $row->getColumns();
|
||||
$columns['growth_percent'] = $growthPercentage;
|
||||
$columns['growth_percent_numeric'] = str_replace('%', '', $growthPercentage);
|
||||
$columns['grown'] = '-' != substr($growthPercentage, 0 , 1);
|
||||
$columns['value_old'] = $oldValue;
|
||||
$columns['value_new'] = $newValue;
|
||||
$columns['difference'] = $difference;
|
||||
$columns['importance'] = abs($difference);
|
||||
$columns['isDisappeared'] = $disappeared;
|
||||
$columns['isNew'] = $isNew;
|
||||
$columns['isMover'] = $isMover;
|
||||
|
||||
$table->addRowFromArray(array(DataTable\Row::COLUMNS => $columns));
|
||||
}
|
||||
}
|
||||
54
www/analytics/plugins/Insights/DataTable/Filter/Limit.php
Normal file
54
www/analytics/plugins/Insights/DataTable/Filter/Limit.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?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\Insights\DataTable\Filter;
|
||||
use Piwik\DataTable\BaseFilter;
|
||||
|
||||
/**
|
||||
* Limits the number of positive and negative values. A value is considered as positive if the value of $columnToRead
|
||||
* is 0 or higher. A value is considered as negative in all other cases (< 0).
|
||||
*/
|
||||
class Limit extends BaseFilter
|
||||
{
|
||||
private $limitPositive;
|
||||
private $limitNegative;
|
||||
private $columnToRead;
|
||||
|
||||
public function __construct($table, $columnToRead, $limitPositiveValues, $limitNegativeValues)
|
||||
{
|
||||
$this->columnToRead = $columnToRead;
|
||||
$this->limitPositive = (int) $limitPositiveValues;
|
||||
$this->limitNegative = (int) $limitNegativeValues;
|
||||
}
|
||||
|
||||
public function filter($table)
|
||||
{
|
||||
$countIncreaser = 0;
|
||||
$countDecreaser = 0;
|
||||
|
||||
foreach ($table->getRows() as $key => $row) {
|
||||
|
||||
if ($row->getColumn($this->columnToRead) >= 0) {
|
||||
|
||||
$countIncreaser++;
|
||||
|
||||
if ($countIncreaser > $this->limitPositive) {
|
||||
$table->deleteRow($key);
|
||||
}
|
||||
|
||||
} else {
|
||||
$countDecreaser++;
|
||||
|
||||
if ($countDecreaser > $this->limitNegative) {
|
||||
$table->deleteRow($key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?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\Insights\DataTable\Filter;
|
||||
|
||||
use Piwik\DataTable\BaseFilter;
|
||||
use Piwik\DataTable;
|
||||
|
||||
/**
|
||||
* A row will be deleted if a positive value of $columnToRead is lower than the $minPositiveValue or if the negative
|
||||
* value of $columnToRead is higher than the $minNegativeValue.
|
||||
* That means a row will be deleted if the value is between $minNegativeValue and $minPositiveValue.
|
||||
*/
|
||||
class MinGrowth extends BaseFilter
|
||||
{
|
||||
private $minPositiveValue;
|
||||
private $minNegativeValue;
|
||||
private $columnToRead;
|
||||
|
||||
public function __construct($table, $columnToRead, $minPositiveValue, $minNegativeValue)
|
||||
{
|
||||
$this->columnToRead = $columnToRead;
|
||||
$this->minPositiveValue = $minPositiveValue;
|
||||
$this->minNegativeValue = $minNegativeValue;
|
||||
}
|
||||
|
||||
public function filter($table)
|
||||
{
|
||||
if (!$this->minPositiveValue && !$this->minNegativeValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($table->getRows() as $key => $row) {
|
||||
|
||||
$growthNumeric = $row->getColumn($this->columnToRead);
|
||||
|
||||
if ($growthNumeric >= $this->minPositiveValue && $growthNumeric >= 0) {
|
||||
continue;
|
||||
} elseif ($growthNumeric <= $this->minNegativeValue && $growthNumeric < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table->deleteRow($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
www/analytics/plugins/Insights/DataTable/Filter/OrderBy.php
Normal file
92
www/analytics/plugins/Insights/DataTable/Filter/OrderBy.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?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\Insights\DataTable\Filter;
|
||||
|
||||
use Piwik\DataTable\BaseFilter;
|
||||
use Piwik\DataTable\Row;
|
||||
|
||||
/**
|
||||
* Goal is to list all positive values first (the higher the better) and then all negative values (the lower the better).
|
||||
*
|
||||
* 40%
|
||||
* 20%
|
||||
* 0%
|
||||
* -40%
|
||||
* -20%
|
||||
*/
|
||||
class OrderBy extends BaseFilter
|
||||
{
|
||||
private $columnsToCheck;
|
||||
|
||||
public function __construct($table, $columnToRead, $columnSecondOrder, $columnThirdOrder = '')
|
||||
{
|
||||
$this->columnsToCheck = array($columnToRead, $columnSecondOrder, $columnThirdOrder);
|
||||
}
|
||||
|
||||
public function filter($table)
|
||||
{
|
||||
if (!$table->getRowsCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table->sort(array($this, 'sort'), $this->columnsToCheck[0]);
|
||||
}
|
||||
|
||||
public function sort(Row $a, Row $b)
|
||||
{
|
||||
foreach ($this->columnsToCheck as $column) {
|
||||
if ($column) {
|
||||
|
||||
$valA = $a->getColumn($column);
|
||||
$valB = $b->getColumn($column);
|
||||
$sort = $this->sortVal($valA, $valB);
|
||||
|
||||
if (isset($sort)) {
|
||||
return $sort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function sortVal($valA, $valB)
|
||||
{
|
||||
if ((!isset($valA) || $valA === false) && (!isset($valB) || $valB === false)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!isset($valA) || $valA === false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!isset($valB) || $valB === false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($valA === $valB) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($valA >= 0 && $valB < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($valA < 0 && $valB < 0) {
|
||||
return $valA < $valB ? -1 : 1;
|
||||
}
|
||||
|
||||
if ($valA != $valB) {
|
||||
return $valA < $valB ? 1 : -1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
288
www/analytics/plugins/Insights/InsightReport.php
Normal file
288
www/analytics/plugins/Insights/InsightReport.php
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
<?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\Insights;
|
||||
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Piwik;
|
||||
|
||||
/**
|
||||
* Insight report generator
|
||||
*/
|
||||
class InsightReport
|
||||
{
|
||||
const ORDER_BY_RELATIVE = 'relative';
|
||||
const ORDER_BY_ABSOLUTE = 'absolute';
|
||||
const ORDER_BY_IMPORTANCE = 'importance';
|
||||
|
||||
/**
|
||||
* @param array $reportMetadata
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param string $lastDate
|
||||
* @param string $metric
|
||||
* @param DataTable $currentReport
|
||||
* @param DataTable $lastReport
|
||||
* @param int $totalValue
|
||||
* @param int $lastTotalValue
|
||||
* @param string $orderBy
|
||||
* @param int $limitIncreaser
|
||||
* @param int $limitDecreaser
|
||||
* @return DataTable
|
||||
*/
|
||||
public function generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser)
|
||||
{
|
||||
$totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
|
||||
|
||||
$minMoversPercent = 1;
|
||||
|
||||
if ($totalEvolution >= 100) {
|
||||
// eg change from 50 to 150 = 200%
|
||||
$factor = (int) ceil($totalEvolution / 500);
|
||||
$minGrowthPercentPositive = $totalEvolution + ($factor * 40); // min +240%
|
||||
$minGrowthPercentNegative = -70; // min -70%
|
||||
$minDisappearedPercent = 8; // min 12
|
||||
$minNewPercent = min(($totalEvolution / 100) * 3, 10); // min 6% = min 10 of total visits up to max 10%
|
||||
|
||||
} elseif ($totalEvolution >= 0) {
|
||||
// eg change from 50 to 75 = 50%
|
||||
$minGrowthPercentPositive = $totalEvolution + 20; // min 70%
|
||||
$minGrowthPercentNegative = -1 * $minGrowthPercentPositive; // min -70%
|
||||
$minDisappearedPercent = 7;
|
||||
$minNewPercent = 5;
|
||||
} else {
|
||||
// eg change from 50 to 25 = -50%
|
||||
$minGrowthPercentNegative = $totalEvolution - 20; // min -70%
|
||||
$minGrowthPercentPositive = abs($minGrowthPercentNegative); // min 70%
|
||||
$minDisappearedPercent = 7;
|
||||
$minNewPercent = 5;
|
||||
}
|
||||
|
||||
if ($totalValue < 200 && $totalValue != 0) {
|
||||
// force at least a change of 2 visits
|
||||
$minMoversPercent = (int) ceil(2 / ($totalValue / 100));
|
||||
$minNewPercent = max($minNewPercent, $minMoversPercent);
|
||||
$minDisappearedPercent = max($minDisappearedPercent, $minMoversPercent);
|
||||
}
|
||||
|
||||
$dataTable = $this->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser);
|
||||
|
||||
$this->addMoversAndShakersMetadata($dataTable, $totalValue, $lastTotalValue);
|
||||
|
||||
return $dataTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends an already generated insight report by adding a column "isMoverAndShaker" whether a row is also a
|
||||
* "Mover and Shaker" or not.
|
||||
*
|
||||
* Avoids the need to fetch all reports again when we already have the currentReport/lastReport
|
||||
*/
|
||||
public function markMoversAndShakers(DataTable $insight, $currentReport, $lastReport, $totalValue, $lastTotalValue)
|
||||
{
|
||||
if (!$insight->getRowsCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$limitIncreaser = max($insight->getRowsCount(), 3);
|
||||
$limitDecreaser = max($insight->getRowsCount(), 3);
|
||||
|
||||
$lastDate = $insight->getMetadata('lastDate');
|
||||
$date = $insight->getMetadata('date');
|
||||
$period = $insight->getMetadata('period');
|
||||
$metric = $insight->getMetadata('metric');
|
||||
$orderBy = $insight->getMetadata('orderBy');
|
||||
$reportMetadata = $insight->getMetadata('report');
|
||||
|
||||
$shakers = $this->generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser);
|
||||
|
||||
foreach ($insight->getRows() as $row) {
|
||||
$label = $row->getColumn('label');
|
||||
|
||||
if ($shakers->getRowFromLabel($label)) {
|
||||
$row->setColumn('isMoverAndShaker', true);
|
||||
} else {
|
||||
$row->setColumn('isMoverAndShaker', false);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addMoversAndShakersMetadata($insight, $totalValue, $lastTotalValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $reportMetadata
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param string $lastDate
|
||||
* @param string $metric
|
||||
* @param DataTable $currentReport
|
||||
* @param DataTable $lastReport
|
||||
* @param int $totalValue
|
||||
* @param int $minMoversPercent Exclude rows who moved and the difference is not at least min percent
|
||||
* visits of totalVisits. -1 excludes movers.
|
||||
* @param int $minNewPercent Exclude rows who are new and the difference is not at least min percent
|
||||
* visits of totalVisits. -1 excludes all new.
|
||||
* @param int $minDisappearedPercent Exclude rows who are disappeared and the difference is not at least min
|
||||
* percent visits of totalVisits. -1 excludes all disappeared.
|
||||
* @param int $minGrowthPercentPositive The actual growth of a row must be at least percent compared to the
|
||||
* previous value (not total value)
|
||||
* @param int $minGrowthPercentNegative The actual growth of a row must be lower percent compared to the
|
||||
* previous value (not total value)
|
||||
* @param string $orderBy Order by absolute, relative, importance
|
||||
* @param int $limitIncreaser
|
||||
* @param int $limitDecreaser
|
||||
*
|
||||
* @return DataTable
|
||||
*/
|
||||
public function generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser)
|
||||
{
|
||||
$minChangeMovers = $this->getMinVisits($totalValue, $minMoversPercent);
|
||||
$minIncreaseNew = $this->getMinVisits($totalValue, $minNewPercent);
|
||||
$minDecreaseDisappeared = $this->getMinVisits($totalValue, $minDisappearedPercent);
|
||||
|
||||
$dataTable = new DataTable();
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\Insight',
|
||||
array(
|
||||
$currentReport,
|
||||
$lastReport,
|
||||
$metric,
|
||||
$considerMovers = (-1 !== $minMoversPercent),
|
||||
$considerNew = (-1 !== $minNewPercent),
|
||||
$considerDisappeared = (-1 !== $minDisappearedPercent)
|
||||
)
|
||||
);
|
||||
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth',
|
||||
array(
|
||||
'growth_percent_numeric',
|
||||
$minGrowthPercentPositive,
|
||||
$minGrowthPercentNegative
|
||||
)
|
||||
);
|
||||
|
||||
if ($minIncreaseNew) {
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
|
||||
array(
|
||||
'difference',
|
||||
$minIncreaseNew,
|
||||
'isNew'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($minChangeMovers) {
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
|
||||
array(
|
||||
'difference',
|
||||
$minChangeMovers,
|
||||
'isMover'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($minDecreaseDisappeared) {
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
|
||||
array(
|
||||
'difference',
|
||||
$minDecreaseDisappeared,
|
||||
'isDisappeared'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\OrderBy',
|
||||
array(
|
||||
$this->getOrderByColumn($orderBy),
|
||||
$orderBy === self::ORDER_BY_RELATIVE ? $this->getOrderByColumn(self::ORDER_BY_ABSOLUTE) : $this->getOrderByColumn(self::ORDER_BY_RELATIVE),
|
||||
$metric
|
||||
)
|
||||
);
|
||||
|
||||
$dataTable->filter(
|
||||
'Piwik\Plugins\Insights\DataTable\Filter\Limit',
|
||||
array(
|
||||
'growth_percent_numeric',
|
||||
$limitIncreaser,
|
||||
$limitDecreaser
|
||||
)
|
||||
);
|
||||
|
||||
$metricName = $metric;
|
||||
if (!empty($reportMetadata['metrics'][$metric])) {
|
||||
$metricName = $reportMetadata['metrics'][$metric];
|
||||
}
|
||||
|
||||
$dataTable->setMetadataValues(array(
|
||||
'reportName' => $reportMetadata['name'],
|
||||
'metricName' => $metricName,
|
||||
'date' => $date,
|
||||
'lastDate' => $lastDate,
|
||||
'period' => $period,
|
||||
'report' => $reportMetadata,
|
||||
'totalValue' => $totalValue,
|
||||
'orderBy' => $orderBy,
|
||||
'metric' => $metric,
|
||||
'minChangeMovers' => $minChangeMovers,
|
||||
'minIncreaseNew' => $minIncreaseNew,
|
||||
'minDecreaseDisappeared' => $minDecreaseDisappeared,
|
||||
'minGrowthPercentPositive' => $minGrowthPercentPositive,
|
||||
'minGrowthPercentNegative' => $minGrowthPercentNegative,
|
||||
'minMoversPercent' => $minMoversPercent,
|
||||
'minNewPercent' => $minNewPercent,
|
||||
'minDisappearedPercent' => $minDisappearedPercent
|
||||
));
|
||||
|
||||
return $dataTable;
|
||||
}
|
||||
|
||||
private function getOrderByColumn($orderBy)
|
||||
{
|
||||
if (self::ORDER_BY_RELATIVE == $orderBy) {
|
||||
$orderByColumn = 'growth_percent_numeric';
|
||||
} elseif (self::ORDER_BY_ABSOLUTE == $orderBy) {
|
||||
$orderByColumn = 'difference';
|
||||
} elseif (self::ORDER_BY_IMPORTANCE == $orderBy) {
|
||||
$orderByColumn = 'importance';
|
||||
} else {
|
||||
throw new \Exception('Unsupported orderBy');
|
||||
}
|
||||
|
||||
return $orderByColumn;
|
||||
}
|
||||
|
||||
private function getMinVisits($totalValue, $percent)
|
||||
{
|
||||
if ($percent <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$minVisits = ceil(($totalValue / 100) * $percent);
|
||||
|
||||
return (int) $minVisits;
|
||||
}
|
||||
|
||||
private function addMoversAndShakersMetadata(DataTable $dataTable, $totalValue, $lastTotalValue)
|
||||
{
|
||||
$totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
|
||||
|
||||
$dataTable->setMetadata('lastTotalValue', $lastTotalValue);
|
||||
$dataTable->setMetadata('evolutionTotal', $totalEvolution);
|
||||
$dataTable->setMetadata('evolutionDifference', $totalValue - $lastTotalValue);
|
||||
}
|
||||
|
||||
private function getTotalEvolution($totalValue, $lastTotalValue)
|
||||
{
|
||||
return Piwik::getPercentageSafe($totalValue - $lastTotalValue, $lastTotalValue, 1);
|
||||
}
|
||||
}
|
||||
51
www/analytics/plugins/Insights/Insights.php
Normal file
51
www/analytics/plugins/Insights/Insights.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?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\Insights;
|
||||
|
||||
use Piwik\WidgetsList;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Insights extends \Piwik\Plugin
|
||||
{
|
||||
/**
|
||||
* @see Piwik\Plugin::getListHooksRegistered
|
||||
*/
|
||||
public function getListHooksRegistered()
|
||||
{
|
||||
return array(
|
||||
'WidgetsList.addWidgets' => 'addWidgets',
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
|
||||
'ViewDataTable.addViewDataTable' => 'getAvailableVisualizations'
|
||||
);
|
||||
}
|
||||
|
||||
public function getAvailableVisualizations(&$visualizations)
|
||||
{
|
||||
$visualizations[] = __NAMESPACE__ . '\\Visualizations\\Insight';
|
||||
}
|
||||
|
||||
public function addWidgets()
|
||||
{
|
||||
WidgetsList::add('Insights_WidgetCategory', 'Insights_OverviewWidgetTitle', 'Insights', 'getInsightsOverview');
|
||||
WidgetsList::add('Insights_WidgetCategory', 'Insights_MoversAndShakersWidgetTitle', 'Insights', 'getOverallMoversAndShakers');
|
||||
}
|
||||
|
||||
public function getStylesheetFiles(&$stylesheets)
|
||||
{
|
||||
$stylesheets[] = "plugins/Insights/stylesheets/insightVisualization.less";
|
||||
}
|
||||
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = "plugins/Insights/javascripts/insightsDataTable.js";
|
||||
}
|
||||
|
||||
}
|
||||
120
www/analytics/plugins/Insights/Model.php
Normal file
120
www/analytics/plugins/Insights/Model.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?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\Insights;
|
||||
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Period\Range;
|
||||
use Piwik\Plugins\API\ProcessedReport;
|
||||
use Piwik\API\Request as ApiRequest;
|
||||
use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI;
|
||||
|
||||
/**
|
||||
* API for plugin Insights
|
||||
*
|
||||
* @method static \Piwik\Plugins\Insights\API getInstance()
|
||||
*/
|
||||
class Model
|
||||
{
|
||||
|
||||
public function requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment)
|
||||
{
|
||||
$report = $this->getReportByUniqueId($idSite, $reportUniqueId);
|
||||
|
||||
$params = array(
|
||||
'method' => $report['module'] . '.' . $report['action'],
|
||||
'format' => 'original',
|
||||
'idSite' => $idSite,
|
||||
'period' => $period,
|
||||
'date' => $date,
|
||||
'filter_limit' => 1000,
|
||||
'showColumns' => $metric
|
||||
);
|
||||
|
||||
if (!empty($segment)) {
|
||||
$params['segment'] = $segment;
|
||||
}
|
||||
|
||||
if (!empty($report['parameters']) && is_array($report['parameters'])) {
|
||||
$params = array_merge($params, $report['parameters']);
|
||||
}
|
||||
|
||||
$request = new ApiRequest($params);
|
||||
$table = $request->process();
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function getLastDate($date, $period, $comparedToXPeriods)
|
||||
{
|
||||
$pastDate = Range::getDateXPeriodsAgo(abs($comparedToXPeriods), $date, $period);
|
||||
|
||||
if (empty($pastDate[0])) {
|
||||
throw new \Exception('Not possible to compare this date/period combination');
|
||||
}
|
||||
|
||||
return $pastDate[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the $totalValue (eg 5500 visits) or the total value of the report
|
||||
* (eg 2500 visits of 5500 total visits as for instance only 2500 visits came to the website using a search engine).
|
||||
*
|
||||
* If the metric total (2500) is much lower than $totalValue, the metric total will be returned, otherwise the
|
||||
* $totalValue
|
||||
*/
|
||||
public function getRelevantTotalValue(DataTable $currentReport, $metric, $totalValue)
|
||||
{
|
||||
$totalMetric = $this->getMetricTotalValue($currentReport, $metric);
|
||||
|
||||
if ($totalMetric > $totalValue) {
|
||||
return $totalMetric;
|
||||
}
|
||||
|
||||
if (($totalMetric * 2) < $totalValue) {
|
||||
return $totalMetric;
|
||||
}
|
||||
|
||||
return $totalValue;
|
||||
}
|
||||
|
||||
public function getTotalValue($idSite, $period, $date, $metric)
|
||||
{
|
||||
$visits = VisitsSummaryAPI::getInstance()->get($idSite, $period, $date, false, array($metric));
|
||||
$firstRow = $visits->getFirstRow();
|
||||
|
||||
if (empty($firstRow)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$totalValue = $firstRow->getColumn($metric);
|
||||
|
||||
return (int) $totalValue;
|
||||
}
|
||||
|
||||
public function getMetricTotalValue(DataTable $currentReport, $metric)
|
||||
{
|
||||
$totals = $currentReport->getMetadata('totals');
|
||||
|
||||
if (!empty($totals[$metric])) {
|
||||
$totalValue = (int) $totals[$metric];
|
||||
} else {
|
||||
$totalValue = 0;
|
||||
}
|
||||
|
||||
return $totalValue;
|
||||
}
|
||||
|
||||
public function getReportByUniqueId($idSite, $reportUniqueId)
|
||||
{
|
||||
$processedReport = new ProcessedReport();
|
||||
$report = $processedReport->getReportMetadataByUniqueId($idSite, $reportUniqueId);
|
||||
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
121
www/analytics/plugins/Insights/Visualizations/Insight.php
Normal file
121
www/analytics/plugins/Insights/Visualizations/Insight.php
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
<?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\Insights\Visualizations;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Period\Range;
|
||||
use Piwik\Plugin\ViewDataTable;
|
||||
use Piwik\Plugin\Visualization;
|
||||
use Piwik\Plugins\Insights\API;
|
||||
use Piwik\Plugins\Insights\Model;
|
||||
|
||||
/**
|
||||
* InsightsVisualization Visualization.
|
||||
*
|
||||
* @property Insight\RequestConfig $requestConfig
|
||||
*/
|
||||
class Insight extends Visualization
|
||||
{
|
||||
const ID = 'insightsVisualization';
|
||||
const TEMPLATE_FILE = '@Insights/insightVisualization.twig';
|
||||
const FOOTER_ICON_TITLE = 'Insights';
|
||||
const FOOTER_ICON = 'plugins/Insights/images/idea.png';
|
||||
|
||||
public function beforeLoadDataTable()
|
||||
{
|
||||
if (!self::canDisplayViewDataTable($this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->requestConfig->filter_limit) {
|
||||
$this->requestConfig->filter_limit = 10;
|
||||
}
|
||||
|
||||
$report = $this->requestConfig->apiMethodToRequestDataTable;
|
||||
$report = str_replace('.', '_', $report);
|
||||
|
||||
$this->requestConfig->apiMethodToRequestDataTable = 'Insights.getInsights';
|
||||
|
||||
$this->requestConfig->request_parameters_to_modify = array(
|
||||
'reportUniqueId' => $report,
|
||||
'minImpactPercent' => $this->requestConfig->min_impact_percent,
|
||||
'minGrowthPercent' => $this->requestConfig->min_growth_percent,
|
||||
'comparedToXPeriods' => $this->requestConfig->compared_to_x_periods_ago,
|
||||
'orderBy' => $this->requestConfig->order_by,
|
||||
'filterBy' => $this->requestConfig->filter_by,
|
||||
'limitIncreaser' => $this->getLimitIncrease(),
|
||||
'limitDecreaser' => $this->getLimitDecrease(),
|
||||
);
|
||||
}
|
||||
|
||||
private function getLimitIncrease()
|
||||
{
|
||||
$filterLimit = $this->requestConfig->filter_limit;
|
||||
$limitIncrease = 0;
|
||||
|
||||
if ($this->requestConfig->limit_increaser && !$this->requestConfig->limit_decreaser) {
|
||||
$limitIncrease = $filterLimit;
|
||||
} elseif ($this->requestConfig->limit_increaser && $this->requestConfig->limit_decreaser) {
|
||||
$limitIncrease = round($filterLimit / 2);
|
||||
}
|
||||
|
||||
return $limitIncrease;
|
||||
}
|
||||
|
||||
private function getLimitDecrease()
|
||||
{
|
||||
$filterLimit = $this->requestConfig->filter_limit;
|
||||
$limitDecrease = $filterLimit - $this->getLimitIncrease();
|
||||
|
||||
return abs($limitDecrease);
|
||||
}
|
||||
|
||||
public static function getDefaultRequestConfig()
|
||||
{
|
||||
return new Insight\RequestConfig();
|
||||
}
|
||||
|
||||
public function isThereDataToDisplay()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function beforeRender()
|
||||
{
|
||||
$this->config->datatable_js_type = 'InsightsDataTable';
|
||||
$this->config->show_limit_control = true;
|
||||
$this->config->show_pagination_control = false;
|
||||
$this->config->show_offset_information = false;
|
||||
$this->config->show_search = false;
|
||||
|
||||
if (!self::canDisplayViewDataTable($this)) {
|
||||
$this->assignTemplateVar('cannotDisplayReport', true);
|
||||
return;
|
||||
}
|
||||
|
||||
$period = Common::getRequestVar('period', null, 'string');
|
||||
$this->assignTemplateVar('period', $period);
|
||||
}
|
||||
|
||||
public static function canDisplayViewDataTable(ViewDataTable $view)
|
||||
{
|
||||
$period = Common::getRequestVar('period', null, 'string');
|
||||
$date = Common::getRequestVar('date', null, 'string');
|
||||
|
||||
$canGenerateInsights = API::getInstance()->canGenerateInsights($date, $period);
|
||||
|
||||
if (!$canGenerateInsights) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::canDisplayViewDataTable($view);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?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\Insights\Visualizations\Insight;
|
||||
|
||||
use Piwik\Plugins\Insights\InsightReport;
|
||||
use Piwik\Plugins\Insights\Visualizations\Insight;
|
||||
use Piwik\ViewDataTable\RequestConfig as VisualizationRequestConfig;
|
||||
|
||||
class RequestConfig extends VisualizationRequestConfig
|
||||
{
|
||||
public $min_impact_percent = '0.1';
|
||||
public $min_growth_percent = 1;
|
||||
public $compared_to_x_periods_ago = 1;
|
||||
public $order_by = InsightReport::ORDER_BY_ABSOLUTE;
|
||||
public $filter_by = '';
|
||||
public $limit_increaser = '5';
|
||||
public $limit_decreaser = '5';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->disable_generic_filters = true;
|
||||
$this->disable_queued_filters = true;
|
||||
|
||||
$properties = array(
|
||||
'min_growth_percent',
|
||||
'order_by',
|
||||
'compared_to_x_periods_ago',
|
||||
'filter_by',
|
||||
'limit_increaser',
|
||||
'limit_decreaser',
|
||||
'filter_limit'
|
||||
);
|
||||
|
||||
$this->addPropertiesThatShouldBeAvailableClientSide($properties);
|
||||
$this->addPropertiesThatCanBeOverwrittenByQueryParams($properties);
|
||||
}
|
||||
|
||||
}
|
||||
BIN
www/analytics/plugins/Insights/images/idea.png
Normal file
BIN
www/analytics/plugins/Insights/images/idea.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 364 B |
118
www/analytics/plugins/Insights/javascripts/insightsDataTable.js
Normal file
118
www/analytics/plugins/Insights/javascripts/insightsDataTable.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($, require) {
|
||||
|
||||
var exports = require('piwik/UI'),
|
||||
DataTable = exports.DataTable,
|
||||
dataTablePrototype = DataTable.prototype;
|
||||
|
||||
var UIControl = exports.UIControl;
|
||||
|
||||
function getValueFromEvent(event)
|
||||
{
|
||||
return event.target.value ? event.target.value : $(event.target).attr('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* UI control that handles extra functionality for Actions datatables.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
exports.InsightsDataTable = function (element) {
|
||||
this.parentAttributeParent = '';
|
||||
this.parentId = '';
|
||||
this.disabledRowDom = {}; // to handle double click on '+' row
|
||||
|
||||
if ($(element).attr('data-table-onlyinsightsinit')) {
|
||||
// overview-widget
|
||||
UIControl.call(this, element);
|
||||
this._init($(element));
|
||||
this.workingDivId = this._createDivId();
|
||||
$(element).attr('id', this.workingDivId);
|
||||
|
||||
} else {
|
||||
DataTable.call(this, element);
|
||||
}
|
||||
};
|
||||
|
||||
$.extend(exports.InsightsDataTable.prototype, dataTablePrototype, {
|
||||
|
||||
handleRowActions: function () {},
|
||||
|
||||
_init: function (domElem) {
|
||||
this.initShowIncreaseOrDecrease(domElem);
|
||||
this.initOrderBy(domElem);
|
||||
this.initComparedToXPeriodsAgo(domElem);
|
||||
this.initFilterBy(domElem);
|
||||
this.setFixWidthToMakeEllipsisWork(domElem);
|
||||
},
|
||||
|
||||
setFixWidthToMakeEllipsisWork: function (domElem) {
|
||||
var width = domElem.width();
|
||||
if (width) {
|
||||
$('td.label', domElem).width(parseInt(width * 0.50, 10));
|
||||
}
|
||||
},
|
||||
|
||||
_changeParameter: function (params) {
|
||||
|
||||
var widgetParams = {};
|
||||
|
||||
for (var index in params) {
|
||||
if (params.hasOwnProperty(index)) {
|
||||
this.param[index] = params[index];
|
||||
widgetParams[index] = params[index];
|
||||
}
|
||||
}
|
||||
|
||||
this.notifyWidgetParametersChange(this.$element, widgetParams);
|
||||
},
|
||||
|
||||
_changeParameterAndReload: function (params) {
|
||||
this._changeParameter(params);
|
||||
this.reloadAjaxDataTable(true);
|
||||
},
|
||||
|
||||
initShowIncreaseOrDecrease: function (domElem) {
|
||||
var self = this;
|
||||
$('[name=showIncreaseOrDecrease]', domElem).bind('change', function (event) {
|
||||
var value = getValueFromEvent(event);
|
||||
|
||||
self._changeParameterAndReload({
|
||||
limit_increaser: (value == 'both' || value == 'increase') ? '5' : '0',
|
||||
limit_decreaser: (value == 'both' || value == 'decrease') ? '5' : '0'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
initOrderBy: function (domElem) {
|
||||
var self = this;
|
||||
$('[name=orderBy]', domElem).bind('change', function (event) {
|
||||
self._changeParameterAndReload({order_by: getValueFromEvent(event)});
|
||||
});
|
||||
$('th[name=orderBy]', domElem).bind('click', function (event) {
|
||||
self._changeParameterAndReload({order_by: getValueFromEvent(event)});
|
||||
});
|
||||
},
|
||||
|
||||
initComparedToXPeriodsAgo: function (domElem) {
|
||||
var self = this;
|
||||
$('[name=comparedToXPeriodsAgo]', domElem).bind('change', function (event) {
|
||||
self._changeParameterAndReload({compared_to_x_periods_ago: getValueFromEvent(event)});
|
||||
});
|
||||
},
|
||||
|
||||
initFilterBy: function (domElem) {
|
||||
var self = this;
|
||||
$('[name=filterBy]', domElem).bind('change', function (event) {
|
||||
self._changeParameterAndReload({filter_by: getValueFromEvent(event)});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, require);
|
||||
15
www/analytics/plugins/Insights/plugin.json
Normal file
15
www/analytics/plugins/Insights/plugin.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Insights",
|
||||
"version": "0.1.0",
|
||||
"description": "Get insights",
|
||||
"theme": false,
|
||||
"license": "GPL v3+",
|
||||
"homepage": "http://piwik.org",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Piwik",
|
||||
"email": "hello@piwik.org",
|
||||
"homepage": "http://piwik.org"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
.dataTableVizInsight {
|
||||
th.orderBy {
|
||||
cursor:pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dataTableVizInsight .dataTableFeatures,
|
||||
.insightsDataTable {
|
||||
|
||||
.controls {
|
||||
padding: 10px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.controlSeparator {
|
||||
height: 1px;
|
||||
border: 0px;
|
||||
background-color: #cccccc;
|
||||
}
|
||||
|
||||
th.orderBy {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
th.orderBy.active {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.title {
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.grown {
|
||||
color:green;
|
||||
}
|
||||
|
||||
.notGrown {
|
||||
color:red;
|
||||
}
|
||||
|
||||
.isMoverAndShaker {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div class="pk-emptyDataTable">
|
||||
{{ 'Insights_DatePeriodCombinationNotSupported'|translate }}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<div class="controls">
|
||||
|
||||
{% if period != 'range' %}
|
||||
|
||||
{{ 'Insights_ControlComparedToDescription'|translate }}
|
||||
|
||||
{% if period == 'day' %}
|
||||
<select size="1" name="comparedToXPeriodsAgo">
|
||||
<option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}>
|
||||
{{ 'Insights_DayComparedToPreviousDay'|translate }}
|
||||
</option>
|
||||
<option value="7" {% if properties.compared_to_x_periods_ago == 7 %}selected{% endif %}>
|
||||
{{ 'Insights_DayComparedToPreviousWeek'|translate }}
|
||||
</option>
|
||||
<option value="365" {% if properties.compared_to_x_periods_ago == 365 %}selected{% endif %}>
|
||||
{{ 'Insights_DayComparedToPreviousYear'|translate }}
|
||||
</option>
|
||||
</select>
|
||||
{% elseif period == 'month' %}
|
||||
<select size="1" name="comparedToXPeriodsAgo">
|
||||
<option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}>
|
||||
{{ 'Insights_MonthComparedToPreviousMonth'|translate }}
|
||||
</option>
|
||||
<option value="12" {% if properties.compared_to_x_periods_ago == 12 %}selected{% endif %}>
|
||||
{{ 'Insights_MonthComparedToPreviousYear'|translate }}
|
||||
</option>
|
||||
</select>
|
||||
{% elseif period == 'week' %}
|
||||
{{ 'Insights_WeekComparedToPreviousWeek'|translate }}
|
||||
{% elseif period == 'year' %}
|
||||
{{ 'Insights_YearComparedToPreviousYear'|translate }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<hr class="controlSeparator" />
|
||||
|
||||
{{ 'Insights_Filter'|translate }}
|
||||
|
||||
<select size="1" name="filterBy" title="{{ 'Insights_ControlFilterByDescription'|translate|e('html_attr') }}">
|
||||
<option {% if not properties.filter_by %}selected{% endif %} value="">
|
||||
{{ 'General_All'|translate }}
|
||||
</option>
|
||||
<option {% if properties.filter_by == 'movers' %}selected{% endif %} value="movers">
|
||||
{{ 'Insights_FilterOnlyMovers'|translate }}
|
||||
</option>
|
||||
<option {% if properties.filter_by == 'new' %}selected{% endif %} value="new">
|
||||
{{ 'Insights_FilterOnlyNew'|translate }}
|
||||
</option>
|
||||
<option {% if properties.filter_by == 'disappeared' %}selected{% endif %} value="disappeared">
|
||||
{{ 'Insights_FilterOnlyDisappeared'|translate }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<select size="1" name="showIncreaseOrDecrease" title="Show increaser and/or decreaser">
|
||||
<option value="both" {% if properties.limit_increaser and properties.limit_decreaser %}selected{%endif%}>
|
||||
{{ 'Insights_FilterIncreaserAndDecreaser'|translate }}
|
||||
</option>
|
||||
<option value="increase" {% if properties.limit_increaser and not properties.limit_decreaser %}selected{%endif%}>
|
||||
{{ 'Insights_FilterOnlyIncreaser'|translate }}
|
||||
</option>
|
||||
<option value="decrease" {% if not properties.limit_increaser and properties.limit_decreaser %}selected{%endif%}>
|
||||
{{ 'Insights_FilterOnlyDecreaser'|translate }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
{% if cannotDisplayReport is defined and cannotDisplayReport %}
|
||||
{% include "@Insights/cannotDisplayReport.twig" %}
|
||||
{% else %}
|
||||
{% set metadata = dataTable.getAllTableMetadata%}
|
||||
{% set consideredGrowth = 'Insights_TitleConsideredInsightsGrowth'|translate(metadata.minGrowthPercentPositive, metadata.lastDate|prettyDate(metadata.period)) %}
|
||||
{% set consideredChanges = '' %}
|
||||
|
||||
{% if metadata.minChangeMovers and metadata.minChangeMovers > 1 %}
|
||||
{% set consideredChanges = 'Insights_IgnoredChanges'|translate(metadata.minChangeMovers) %}
|
||||
{% endif %}
|
||||
|
||||
<div class="insightsDataTable" title="{{ consideredGrowth|e('html_attr') }} {{ consideredChanges|e('html_attr') }}">
|
||||
{% if dataTable.getRowsCount %}
|
||||
<table class="dataTable">
|
||||
|
||||
<thead>
|
||||
{% include "@Insights/table_header.twig" %}
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for row in dataTable.getRows %}
|
||||
{% include "@Insights/table_row.twig" %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="pk-emptyDataTable">
|
||||
{{ 'Insights_NoResultMatchesCriteria'|translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% include "@Insights/insightControls.twig" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{% set allMetadata = reports.getFirstRow.getAllTableMetadata %}
|
||||
{% set consideredGrowth = 'Insights_TitleConsideredInsightsGrowth'|translate(allMetadata.minGrowthPercentPositive, allMetadata.lastDate|prettyDate(allMetadata.period)) %}
|
||||
{% set consideredChanges = '' %}
|
||||
|
||||
{% include "@Insights/overviewWidget.twig" %}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{% set allMetadata = reports.getFirstRow.getAllTableMetadata %}
|
||||
|
||||
{% set consideredGrowth = 'Insights_TitleConsideredMoversAndShakersGrowth'|translate(allMetadata.metricName, allMetadata.lastTotalValue, allMetadata.totalValue, allMetadata.lastDate|prettyDate(allMetadata.period), allMetadata.evolutionTotal) %}
|
||||
{% set consideredChanges = 'Insights_TitleConsideredMoversAndShakersChanges'|translate(allMetadata.minGrowthPercentPositive, allMetadata.minGrowthPercentNegative, allMetadata.minNewPercent, allMetadata.minIncreaseNew, allMetadata.minDisappearedPercent, allMetadata.minDecreaseDisappeared, allMetadata.totalValue) %}
|
||||
|
||||
{% include "@Insights/overviewWidget.twig" %}
|
||||
38
www/analytics/plugins/Insights/templates/overviewWidget.twig
Normal file
38
www/analytics/plugins/Insights/templates/overviewWidget.twig
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<div class="insightsDataTable dataTable"
|
||||
data-table-type="InsightsDataTable"
|
||||
data-table-onlyinsightsinit="1">
|
||||
{% if reports.getColumns|length > 0 %}
|
||||
|
||||
<table class="dataTable"
|
||||
title="{{ consideredGrowth|e('html_attr') }} {{ consideredChanges|e('html_attr') }}">
|
||||
{% for dataTable in reports.getDataTables() if dataTable.getRowsCount > 0 %}
|
||||
{% set metadata = dataTable.getAllTableMetadata %}
|
||||
|
||||
<thead>
|
||||
{% include "@Insights/table_header.twig" %}
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for row in dataTable.getRows %}
|
||||
{% include "@Insights/table_row.twig" %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" defer="defer">
|
||||
$(document).ready(function () {
|
||||
require('piwik/UI/DataTable').initNewDataTables();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="pk-emptyDataTable"
|
||||
title="{{ consideredGrowth|e('html_attr') }} {{ consideredChanges|e('html_attr') }}">
|
||||
{{ 'Insights_NoResultMatchesCriteria'|translate }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
13
www/analytics/plugins/Insights/templates/table_header.twig
Normal file
13
www/analytics/plugins/Insights/templates/table_header.twig
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<tr>
|
||||
<th class="label">
|
||||
{{ metadata.reportName }}
|
||||
</th>
|
||||
<th class="label orderBy {% if 'absolute' == properties.order_by %}active{% endif %}"
|
||||
name="orderBy" value="absolute">
|
||||
{{ metadata.metricName }}
|
||||
</th>
|
||||
<th class="label orderBy {% if 'relative' == properties.order_by %}active{% endif %}"
|
||||
name="orderBy" value="relative">
|
||||
{{ 'MultiSites_Evolution'|translate }}
|
||||
</th>
|
||||
</tr>
|
||||
29
www/analytics/plugins/Insights/templates/table_row.twig
Normal file
29
www/analytics/plugins/Insights/templates/table_row.twig
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{% if row.getColumn('isDisappeared') %}
|
||||
{% set rowTitle = 'Insights_TitleRowDisappearedDetails'|translate(row.getColumn('label'), row.getColumn('value_old'), metadata.date|prettyDate(metadata.period), metadata.lastDate|prettyDate(metadata.period)) %}
|
||||
{% elseif row.getColumn('isNew') %}
|
||||
{% set rowTitle = 'Insights_TitleRowNewDetails'|translate(row.getColumn('label'), row.getColumn('value_new'), metadata.lastDate|prettyDate(metadata.period)) %}
|
||||
{% else %}
|
||||
{% set rowTitle = 'Insights_TitleRowChangeDetails'|translate(row.getColumn('label'), row.getColumn('value_old'), metadata.lastDate|prettyDate(metadata.period), row.getColumn('value_new'), metadata.date|prettyDate(metadata.period), metadata.metricName) %}
|
||||
{% endif %}
|
||||
|
||||
{% set rowTitleShaker = '' %}
|
||||
{% if row.getColumn('isMoverAndShaker') %}
|
||||
{% set rowTitleShaker = 'Insights_TitleRowMoverAndShaker'|translate %}
|
||||
{% endif %}
|
||||
|
||||
<tr title="{{ rowTitle|e('html_attr') }} {{ rowTitleShaker|e('html_attr') }}"
|
||||
class="{% if row.getColumn('isMoverAndShaker') %}isMoverAndShaker{% endif %}">
|
||||
<td class="label">
|
||||
<span class="title">
|
||||
{{ row.getColumn('label') }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
{% if row.getColumn('grown') %}
|
||||
<td>+{{ row.getColumn('difference') }}</td>
|
||||
<td class="grown">+{{ row.getColumn('growth_percent') }}</td>
|
||||
{% else %}
|
||||
<td>{{ row.getColumn('difference') }}</td>
|
||||
<td class="notGrown">{{ row.getColumn('growth_percent') }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
Loading…
Add table
Add a link
Reference in a new issue